] {
def point[A](a: => A): Identity[A] = sys error "whatever"
def bind[A, B](fa: Identity[A])(f: A => Identity[B]): Identity[B] =
sys error "whatever"
}
case class IdentityT[M[_], A](val value: M[A])
object IdentityT {
implicit def idtmonad[M[_]: Monad, A, B] =
new Monad[({type λ[α] = IdentityT[M, α]})#λ] {
def point[A](a: => A): IdentityT[M, A] = sys error "whatever"
def bind[A, B](fa: IdentityT[M, A])(f: A => IdentityT[M, B]
): IdentityT[M, B] =
sys error "whatever"
}
}
And so we
scala> val i = Identity(42)
i: Identity[Int] = Identity(42)
scala> val it = IdentityT(i)
it: IdentityT[Identity,Int] = IdentityT(Identity(42))
scala> val itt = IdentityT(it)
<console>:13: error: no type parameters for method apply: (value: M[A])IdentityT[M,A] in object IdentityT exist so that it can be applied to arguments (IdentityT[Identity,Int])
--- because ---
argument expression's type is not compatible with formal parameter type;
found : IdentityT[Identity,Int]
required: ?M
val itt = IdentityT(it)
^
The essence of the problem is that scalac is trying to fill a
M[A] argument with something of the shape
X[Y, Z], and doesn't know how.
scalaz provides the tools to solve your problem. Add to IdentityT's companion:
import scalaz.Unapply
/** Unpack `M0[F0[_], B0]` to `[b]M0[F0, b]` and `B`. */
implicit def unapplyMFB2[TC[_[_]], M0[_[_], _], F0[_], B0
](implicit TC0: TC[({type λ[α] = M0[F0, α]})#λ]) =
new Unapply[TC, M0[F0, B0]] {
type M[X] = M0[F0, X]
type A = B0
def TC = TC0
def apply(ma: M0[F0, B0]) = ma
}
def lift[MA](fa: MA)(implicit U: Unapply[Monad, MA]): IdentityT[U.M, U.A] =
IdentityT(U(fa))
Just like before (please forgive me for adding newlines to REPL's output):
scala> val i = Identity(42)
i: Identity[Int] = Identity(42)
scala> val it = IdentityT lift i
it: IdentityT[scalaz.Unapply[scalaz.Monad,Identity[Int]]
{type M[X] = Identity[X]; type A = Int}#M,
Int]
= IdentityT(Identity(42))
scala> it: IdentityT[Identity, Int]
it: IdentityT[Identity, Int]
res1: IdentityT[Identity,Int] = IdentityT(Identity(42))
Note that
it reduced to the type you expected; you can run the reduction above by reading the
it inferred type.
We haven't even used
unapplyMFB2 yet though (which could be included in Unapply.scala in scalaz, if you like):
scala> IdentityT lift res1
res2: IdentityT[scalaz.Unapply[scalaz.Monad,IdentityT[Identity,Int]]
{type M[X] = IdentityT[Identity,X]; type A = Int}#M,
Int]
= IdentityT(IdentityT(Identity(42)))
scala> val itt = IdentityT lift it
itt: IdentityT[scalaz.Unapply[scalaz.Monad,IdentityT[scalaz.Unapply[scalaz.Monad,Identity[Int]]
{type M[X] = Identity[X]; type A = Int}#M,
Int]]
{type M[X] = IdentityT[scalaz.Unapply[scalaz.Monad,Identity[Int]]
{type M[X] = Identity[X]; type A = Int}#M,
X];
type A = Int}#M,
Int]
= IdentityT(IdentityT(Identity(42)))
Note that no matter the form, you get the right result. I'll wait here while you trace what that
itt's Unapply should reduce to:
scala> itt: IdentityT[({type F[A] = IdentityT[Identity, A]})#F, Int]
res3: IdentityT[[A]IdentityT[Identity,A],Int] = IdentityT(IdentityT(Identity(42)))
Now try
IdentityT lift (IdentityT lift (IdentityT lift itt)). I'll wait here again, while you wait for scalac to figure out what you're saying.
I hope you enjoyed this adventure, and have a newfound appreciation for the inference you get when working with
mtl in Haskell.
--
Stephen Compall
^aCollection allSatisfy: [:each|aCondition]: less is better
|