This is a followup to my previous question. Looks like I still did not get it. Now I am trying to compose functions that return 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)
Why doesn't it compile ?
When the Scala compiler expects a type shaped like
M[B]
and you give it something likeWriterT[Id, String, Int]
, it's unfortunately just not smart enough to figure out that you want to fix the first two type parameters and use the monad forWriterT[Id, String, _]
.There are a few possible ways to work around this limitation. The first is to define a type alias:
Now you can provide explicit type parameters (in fact you could do this without the alias, but the type lambdas would make the line twice as long and ten times as unreadable):
Scalaz now provides a nicer solution, though, via Miles Sabin's "unapply trick":
kleisliU
is essentially just a nice version ofKleisli.apply
that uses a new type class (namedUnapply
) behind the scenes to guide the type inference system to the right way to break apart theWriterT[Id, String, Int]
.