RúnarBjarnason完成了观看发人深省的视频“具有价格合理的monad的可组合应用程序架构”,我开始编写Scalaz视频中提供的示例。在为Interact App实现基于编写器的解释器时,我有点意外。这是代码,
sealed trait Interact[A]
case class Ask(prompt: String) extends Interact[String]
case class Tell(msg: String) extends Interact[Unit]
type W[A] = scalaz.Writer[Vector[String], A]
object ConsoleW extends (Interact ~> W) {
def apply[A](i: Interact[A]) = i match {
case Ask(prompt) =>
println(prompt)
Writer(Vector(prompt), readLine)
case Tell(msg) =>
println(msg)
Writer(Vector.empty, ())
}
}
当我试图将ConsoleW提升为无交互式monad的解释器时,编译器暗示我缺少Functor到W的上下文绑定。我很惊讶,因为Writer本身是一个monad,应该给出functor上下文绑定自由。好的,所以我必须明确地写一个仿函数,
implicit val functor = new Functor[W] {
def map[A, B](fa: Writer[Vector[String], A])(f: A => B) =
fa.map(f)
}
这非常愚蠢......因为除了调用Writer本身的map方法之外我基本上什么也没做。现在我可以将ConsoleW提升为解释器。然而,当我尝试使用ConsoleW折叠交互程序时,编译器再次暗示缺少对W的Monad上下文绑定!好吧,这完全出乎意料,让我用勺子喂你,Scalac ......
val prg: Free[({type f[x] = Coyoneda[Interact, x]})#f, Unit] = ???
import scalaz.std.vector._
implicit val monad = new scalaz.Monad[W] {
def point[A](a: => A) = Writer[Vector[String], A](Vector.empty, a)
def bind[A, B](fa: Writer[Vector[String], A])(f: A => Writer[Vector[String], B]) =
fa.flatMap(f)
}
prg.foldMap(Coyoneda.liftTF(ConsoleW))
现在一切都编译好了,编写器Monad可以在程序运行时将所有提示记录到向量中。但这是不完美的,我想创建一个与Writer作为底层Monad的解释器,而不必明确提供它真的是Functor和Monad的证明。知道如何解决这个问题吗?
答案 0 :(得分:0)
只需要导入scalaz.std.vector._,问题就解决了。我对Id.Id如何按原样运作印象深刻,忘记了作家monad的导入应该更复杂。