I'm somewhat familiar with Haskell monad transformers, but new to Scalaz (version 7). I made (what I thought was) a straightforward translation from the following Haskell code:
import Control.Monad.State
type Pass a = StateT String Maybe a
monadTest :: Pass String
monadTest = do
s <- get
return s
to this Scala code:
import scalaz._
import Scalaz._
object StateTest {
type Pass[A] = StateT[Option, String, A]
def monadTest: Pass[String] =
for {
s <- get[String]
} yield s
}
The Haskell code compiles. The Scala fails to compile, with the following error:
[error] .../StateTest.scala:9: type mismatch;
[error] found : scalaz.IndexedStateT[scalaz.Id.Id,String,String,String]
[error] required: StateTest.Pass[String]
[error] (which expands to) scalaz.IndexedStateT[Option,String,String,String]
[error] s <- get[String]
[error] ^
First, it seems scalaz implements StateT
in terms of IndexedStateT
. Ok. But, it seems that the get[String]
monadic value is inferred to have type StateT[Id, String, String]
instead of StateT[Option, String, String]
. Why?
I'm using Scala 2.10.1, scalaz 7.0.0.
In your example, the call to get[String]
is calling the get
method of StateFunctions
, reproduced here:
def get[S]: State[S, S] = init
Where State[S, A]
is an alias for StateT[Id, S, A]
which is an alias for IndexedStateT[Id, S, S, A]
.
Because you are using StateT
, you need to call get
on an instance of StateTMonadState[S, F]
, or StateTMonadState[String, Option]
in your case. The working example is:
import scalaz._
import Scalaz._
object StateTest {
type Pass[A] = StateT[Option, String, A]
val sm = StateT.stateTMonadState[String, Option]
def monadTest: Pass[String] =
for {
s <- sm.get
} yield s
}
The MonadState
instance can also be resolved implicitly via MonadState[F[_, _], S]
but it is less convenient to use due to the type lambda required. See MonadState.scala and StateT.scala for more info.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With