3

这是我之前的问题的后续。看来我还是没明白。现在我正在尝试编写返回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: 错误: 没有适用于方法的类型参数: (f: A => M[B])scalaz.Kleisli[M,A,B] 在对象 Kleisli 中存在,因此它可以应用于参数 (Int => scalaz .WriterT[scalaz.Id.Id,String,Int])
 - - 因为  - -
参数表达式的类型与形参类型不兼容;
 发现:Int => scalaz.WriterT[scalaz.Id.Id,String,Int]
 必需:?A => ?M

              克莱斯利(女) >=> 克莱斯利(女)

为什么不编译?

4

1 回答 1

2

当 Scala 编译器需要一个形状为 like 的类型M[B]并且你给它类似的东西WriterT[Id, String, Int]时,不幸的是它不够聪明,无法确定你想要修复前两个类型参数并使用 monad for WriterT[Id, String, _]

有几种可能的方法可以解决此限制。首先是定义一个类型别名:

type StringWriter[A] = WriterT[Id, String, A]

现在您可以提供显式类型参数(实际上您可以在没有别名的情况下执行此操作,但类型 lambdas会使该行的长度增加一倍,不可读的十倍):

scala> Kleisli[StringWriter, Int, Int](f) >=> Kleisli[StringWriter, Int, Int](f)
res0: scalaz.Kleisli[StringWriter,Int,Int] = Kleisli(<function1>)

不过,Scalaz 现在通过 Miles Sabin 的“不适用技巧”提供了一个更好的解决方案:

val ff = Kleisli.kleisliU(f) >=> Kleisli.kleisliU(f)

kleisliU本质上只是一个不错的版本,它在幕后Kleisli.apply使用一个新的类型类(名为.UnapplyWriterT[Id, String, Int]

于 2014-02-10T18:08:19.597 回答