我对Haskell monad变换器有些熟悉,但对Scalaz(版本7)不熟悉。我从以下Haskell代码中做了(我认为是)直接的翻译:
import Control.Monad.State
type Pass a = StateT String Maybe a
monadTest :: Pass String
monadTest = do
s <- get
return s
这个Scala代码:
import scalaz._
import Scalaz._
object StateTest {
type Pass[A] = StateT[Option, String, A]
def monadTest: Pass[String] =
for {
s <- get[String]
} yield s
}
Haskell代码编译。 Scala无法编译,出现以下错误:
[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] ^
首先,似乎scalaz在StateT
方面实现IndexedStateT
。好。但是,似乎推断get[String]
monadic值的类型为StateT[Id, String, String]
而不是StateT[Option, String, String]
。为什么呢?
我正在使用Scala 2.10.1,scalaz 7.0.0。
答案 0 :(得分:8)
在您的示例中,对get[String]
的调用是调用get
的{{1}}方法,在此处转载:
StateFunctions
其中def get[S]: State[S, S] = init
是State[S, A]
的别名,StateT[Id, S, A]
是IndexedStateT[Id, S, S, A]
的别名。
由于您使用的是StateT
,因此您需要在get
或StateTMonadState[S, F]
的实例上调用StateTMonadState[String, Option]
。工作示例是:
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
}
MonadState
实例也可以通过MonadState[F[_, _], S]
隐式解析,但由于需要lambda类型,因此使用起来不太方便。有关详细信息,请参阅MonadState.scala和StateT.scala。