est*_*lua 3 design-patterns functional-programming scala algebraic-data-types scalaz
在"FP in Scala"一书中,有一种将ADT S用作抽象指令集的方法
sealed trait Console[_]
case class PrintLine(msg: String) extends Console[Unit]
case object ReadLine extends Console[String]
Run Code Online (Sandbox Code Playgroud)
并将它们组合在一起,Free[S, A]然后S将其转换为IO monad.这可以用Scalaz的Free类型完成吗?似乎所有run方法都需要一个仿函数实例S.
是的,你需要一个仿函数,但你可以创建一个仿函数Coyoneda.
Coyoneda将任何F[A]变为a Coyoneda[F,A]并且Coyoneda[F,A]是一个仿函数.
scala> type ConsoleCoyo[A] = Coyoneda[Console, A]
defined type alias ConsoleCoyo
Run Code Online (Sandbox Code Playgroud)
然后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]
Run Code Online (Sandbox Code Playgroud)
所以现在我们有一个免费的monad for console:
scala> type ConsoleMonad[A] = Free.FreeC[ConsoleCoyo,A]
defined type alias ConsoleMonad
Run Code Online (Sandbox Code Playgroud)
另外你会发现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)
Run Code Online (Sandbox Code Playgroud)
所以,例如:
scala> Free.liftFC(ReadLine)
res1: scalaz.Free.FreeC[Console,String] = Suspend(scalaz.Coyoneda$$anon$22@360bb132)
Run Code Online (Sandbox Code Playgroud)