Monad Transformer stacks in Scala

either, monads, scala, stack, state

Solution

The method call `get[Int]` returns an `IndexedStateT[Id, Int, Int, Int]`. Your `Stack[Int]` expands to `IndexedStateT[Inner, Int, Int, Int]` where `Inner` is an `EitherT[Id, String, A]`. This is a bit hard to reason about, so I will simplify your example a bit.

Instead of the `Inner` type alias we create a `StateT` with an `Option`.

type Stack[A] = StateT[Option, Int, A]

The assignment of `get[Int]` will still fail.

val x:Stack[Int] = get[Int]
//type mismatch; 
//  found : scalaz.State[Int,Int]
//    (which expands to) scalaz.IndexedStateT[scalaz.Id.Id,Int,Int,Int]
//  required: Minimal.Stack[Int] 
//    (which expands to) scalaz.IndexedStateT[Option,Int,Int,Int]

In order to fix this problem we need to `lift` the transformer to an `Option`:

val x:Stack[Int] = get[Int].lift[Option]

If you translate that to your example code, you would need to `lift` the `State` to an `Inner` like this. Note that you need to change your definition of `Inner` to be covariant as well:

type Inner[+A] = EitherT[Id, String, A]
type Stack[A] = StateT[Inner, Int, A]

val x:Stack[Int] = get[Int].lift[Inner]

To be able to write this without lifting manually you could introduce an implicit conversion. The full example:

type Inner[+A] = EitherT[Id, String, A]
type Outer[F[+_], A] = StateT[F, Int, A]
type Stack[A] = Outer[Inner, A]

implicit def liftToStack[A](x:Outer[Id, A]):Stack[A] = x.lift[Inner]

def foo: Stack[Int] = for {
  n <- get[Int]
} yield {
  2 * n
}

Problem

I'm learning about monad transformers in Scala but I ran into a problem which I find impossible to solve so far. In my monad transformer stack I compose the Either and the State monad. However, I fail to call functions belonging to one of the two monads: ``` import scalaz._ import Scalaz._ object Minimal { type Inner[A] = EitherT[Id, String, A] type Outer[F[+_], A] = StateT[F,Int,A] type Stack[A] = Outer[Inner, A] def foo:Stack[Int] = for { n <- get[Int] } yield { 2 * n } def main(args: Array[String]): Unit = { val x = foo.eval(8) println(x) } } ``` Fails with the following error message: ``` [error] Minimal.scala:10: type mismatch; [error] found : scalaz.IndexedStateT[scalaz.Id.Id,Int,Int,Int] [error] required: Minimal.Stack[Int] [error] (which expands to) scalaz.IndexedStateT[Minimal.Inner,Int,Int,Int] [error] n <- get[Int] ``` If I change the monad transformer stack to: ``` type Stack[A] = State[Int,A] ``` The program compiles and runs without a problem. Does anybody knows what I do wrong here?

Original source