scala - Kleisli Arrow with Writer in Scala。为什么不编译?

标签 scala monads scalaz kleisli

这是我之前的 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/

相关文章:

scala - Scala 中的 ISO 宏

scala - 使用带有 bintray-sbt 插件的 sbt 时如何发布快照?

java - Java 使用什么类来存储数组以及如何在 Scala 中实例化它?

scala - 为什么 SBT 给我 "not found: object akka"和 "import akka._"?

functional-programming - 当我需要多次存储(当前秒)时避免可变状态

scalaz:如何处理验证中的不同错误类型?

scala - Spark中ALS的实现

scala - 如果定义了选项,则用于在链中应用函数的惯用 Scala

Haskell 方式将 [IO String] 加入 IO String

scala Iterator 中的 scalaz Iteratees