这是我之前的 question 的后续.看来我还是没明白。现在我正在尝试编写返回 Writer monad 的函数。
scala> val f = {x:Int => Writer("doing " + x + ";", x + 1)} f: Int => scalaz.WriterT[scalaz.Id.Id,String,Int] = scala> Kleisli(f) >=> Kleisli(f) :16: error: no type parameters for method apply: (f: A => M[B])scalaz.Kleisli[M,A,B] in object Kleisli exist so that it can be applied to arguments (Int => scalaz.WriterT[scalaz.Id.Id,String,Int]) --- because --- argument expression's type is not compatible with formal parameter type; found : Int => scalaz.WriterT[scalaz.Id.Id,String,Int] required: ?A => ?M Kleisli(f) >=> Kleisli(f)
为什么不编译?
最佳答案
当 Scala 编译器期望一个形如 M[B]
的类型,而你给它一个形如 WriterT[Id, String, Int]
的类型时,不幸的是它并不聪明足以弄清楚您想要修复前两个类型参数并将 monad 用于 WriterT[Id, String, _]
。
有几种可能的方法可以解决此限制。首先是定义类型别名:
type StringWriter[A] = WriterT[Id, String, A]
现在您可以提供显式类型参数(事实上,您可以在没有别名的情况下执行此操作,但是 type lambdas 会使该行的长度增加一倍并且增加十倍不可读):
scala> Kleisli[StringWriter, Int, Int](f) >=> Kleisli[StringWriter, Int, Int](f)
res0: scalaz.Kleisli[StringWriter,Int,Int] = Kleisli(<function1>)
不过,Scalaz 现在通过 Miles Sabin 的 "unapply trick" 提供了一个更好的解决方案:
val ff = Kleisli.kleisliU(f) >=> Kleisli.kleisliU(f)
kleisliU
本质上只是 Kleisli.apply
的一个不错的版本,它在幕后使用一个新的类型类(名为 Unapply
)来指导类型推断系统以正确的方式分解 WriterT[Id, String, Int]
。
关于scala - Kleisli Arrow with Writer in Scala。为什么不编译?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21683776/