2014-02-10 49 views
3

这是我以前的question的后续。看起来我仍然没有得到它。现在我试图编写返回作家 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) 

为什么不编译?

+1

'参数表达式的类型与形式参数类型不兼容; 找到:Int => scalaz.WriterT [scalaz.Id.Id,String,Int] 必需:?A =>?M' –

回答

2

当Scala编译器需要一个类型状如M[B],你给它像WriterT[Id, String, Int]不幸的,这只是没有足够聪明弄清楚,要解决前两个类型的参数,并使用单子的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现在提供了一个更好的解决方案,但通过数萨宾的"unapply trick"

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

kleisliU基本上只是一个很好的版本Kleisli.apply,它在幕后使用一个新类型(名为Unapply)来指导类型推断系统以正确的方式拆分WriterT[Id, String, Int]

+0

谢谢!所有你说的话似乎很合理,但我不明白,我不能只为每个'f'和'g'写'f> => g',而不是所有的'Kleisli','kleisliU'和其他所有的东西都返回_any_ monad ...... :((我还是不明白) – Michael

+3

@迈克尔:“奇迹并不是熊的舞蹈有多好,而是熊的跳舞。” –

+0

好的,我明白了,所有这些都是语言限制。 – Michael