Scala 克莱斯利·阿罗和斯卡拉的作家。为什么';它不编译吗?

Scala 克莱斯利·阿罗和斯卡拉的作家。为什么';它不编译吗?,scala,monads,scalaz,kleisli,Scala,Monads,Scalaz,Kleisli,这是我上一篇文章的后续文章。看来我还是没弄明白。现在我尝试编写返回Writer monad的函数 scala>valf={x:Int=>Writer(“执行”+x+“;”,x+1)} f:Int=>scalaz.WriterT[scalaz.Id.Id,String,Int]= scala>Kleisli(f)>=>Kleisli(f) :16:错误:没有方法应用的类型参数:(f:A=>M[B])对象Kleisli中存在scalaz.Kleisli[M,A,B],因此可以将其应用于参数(Int=

这是我上一篇文章的后续文章。看来我还是没弄明白。现在我尝试编写返回Writer monad的函数

scala>valf={x:Int=>Writer(“执行”+x+“;”,x+1)} f:Int=>scalaz.WriterT[scalaz.Id.Id,String,Int]= scala>Kleisli(f)>=>Kleisli(f) :16:错误:没有方法应用的类型参数:(f:A=>M[B])对象Kleisli中存在scalaz.Kleisli[M,A,B],因此可以将其应用于参数(Int=>scalaz.WriterT[scalaz.Id.Id,String,Int]) ---因为--- 参数表达式的类型与形式参数类型不兼容; 找到:Int=>scalaz.WriterT[scalaz.Id.Id,String,Int] 必需:?A=>?M 克莱斯利(f)>=>克莱斯利(f)
为什么它不编译?

当Scala编译器需要一个类似
M[B]
的类型,而您给它类似
WriterT[Id,String,Int]
的东西时,不幸的是,它不够聪明,无法确定您想要修复前两个类型参数,并将monad用于
WriterT[Id,String,.

有几种可能的方法可以绕过这个限制。第一个是定义类型别名:

type StringWriter[A] = WriterT[Id, String, A]
现在,您可以提供显式类型参数(事实上,您可以在不使用别名的情况下执行此操作,但这样做会使行的长度增加一倍,使其无法读取十倍):


kleisliU
本质上只是
Kleisli.apply
的一个好版本,它在幕后使用一个新的类型类(名为
Unapply
)来引导类型推断系统正确地分解
WriterT[Id,String,Int]

参数表达式的类型与形式参数类型不兼容;找到:Int=>scalaz.WriterT[scalaz.Id.Id,String,Int]必需:?A=>M
谢谢!你所说的一切似乎都很合理,但我不明白,我不能简单地为每个返回任何单子的
f
g
f>=>g
,而不包含所有这些
Kleisli
kleisliU
和所有东西……:(我还是不明白。@Michael:“令人惊奇的不是熊跳得多好,而是熊跳得很好。”好的,我明白了。所有这些都是语言限制。我不明白为什么他们将
Writer
定义为
WriterT
。看起来这会导致编译问题。即使
Writer
也有两个类型参数。对于单参数泛型类型,您只会得到
M[B]
的类型推断(
选项
列表
IO
等)。
type StringWriter[A] = WriterT[Id, String, A]
scala> Kleisli[StringWriter, Int, Int](f) >=> Kleisli[StringWriter, Int, Int](f)
res0: scalaz.Kleisli[StringWriter,Int,Int] = Kleisli(<function1>)
val ff = Kleisli.kleisliU(f) >=> Kleisli.kleisliU(f)