2014-02-10 46 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