scala - 在 Scalaz 中将 Free 与非仿函数一起使用

标签 scala design-patterns functional-programming scalaz algebraic-data-types

在“Scala 中的 FP”一书中,有这种使用 ADT S 作为抽象指令集的方法,例如

sealed trait Console[_]
case class PrintLine(msg: String) extends Console[Unit]
case object ReadLine extends Console[String]

并用 Free[S, A] 组合它们,其中 S 稍后将被转换为 IO monad。 这可以用 Scalaz 的 Free 类型来完成吗?似乎所有 run 方法都需要 S 的仿函数实例。

最佳答案

是的,您需要一个仿函数,但您可以使用 Coyoneda 创建一个仿函数。

Coyoneda 会将任何 F[A] 变成 Coyoneda[F,A]Coyoneda[F,A] 是一个仿函数。

scala> type ConsoleCoyo[A] = Coyoneda[Console, A]
defined type alias ConsoleCoyo

那么 scalaz 的 Free 有一个类型别名就是为了这个:

/** A free monad over the free functor generated by `S` */
type FreeC[S[_], A] = Free[({type f[x] = Coyoneda[S, x]})#f, A]

所以现在我们有一个免费的控制台单子(monad):

scala> type ConsoleMonad[A] = Free.FreeC[ConsoleCoyo,A]
defined type alias ConsoleMonad

您还会发现 scalaz 的 Free 具有将 F[A] 直接提升到 monad 的功能,这很方便:

/** A free monad over a free functor of `S`. */
def liftFC[S[_], A](s: S[A]): FreeC[S, A] =
  liftFU(Coyoneda lift s)

所以,例如:

scala> Free.liftFC(ReadLine)
res1: scalaz.Free.FreeC[Console,String] = Suspend(scalaz.Coyoneda$$anon$22@360bb132)

关于scala - 在 Scalaz 中将 Free 与非仿函数一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25403944/

相关文章:

java - Apache Spark和Scala中数据集的移动平均值

scala - value === 不是类型参数 TKey 的成员(使用 Squeryl)

scala - Scala 2.10反射,如何从案例类中提取字段值,即案例类中的字段列表

scala - Spark 数据帧检查点清理

php - 具有不同设计的两个数据库之间的映射

java - 单例模式: Multiton?

list - 如何在 ocaml 中一次遍历两个列表?

javascript - JavaScript 中的函数式递归方法?不良做法?

Java通过多线程共享对象 - 需要设计模式

scala:在函数(val)中定义默认参数与使用方法(def)