我试图通过移植Dan Piponi本教程中的一些示例来了解Scala中的Monad Transformers:http://blog.sigfpe.com/2006/05/grok-haskell-monad-transformers.html
我做了几件简单的事情:
import Control.Monad.State
import Control.Monad.Identity
test1 = do
a <- get
modify (+1)
b <- get
return (a,b)
test2 = do
a <- get
modify (++"1")
b <- get
return (a,b)
go1 = evalState test1 0
go2 = evalState test2 "0"
变为:
import scalaz._, Scalaz._
val test1 = for {
a <- get[Int]
_ <- modify[Int](1+)
b <- get
} yield (a,b)
val test2 = for {
a <- get[String]
_ <- modify[String](_ + "1")
b <- get
} yield (a,b)
val go1 = test1.eval(0)
val go2 = test2.eval("0")
但是我怎么能将下一个例子移植到Scala?
test3 = do
modify (+ 1)
lift $ modify (++ "1")
a <- get
b <- lift get
return (a,b)
go3 = runIdentity $ evalStateT (evalStateT test3 0) "0"
我使用scalaz 7.1.0-M6获得了这么远:
type SST[F[_],A] = StateT[F,String,A]
type IST[F[_],A] = StateT[F,Int,A]
val p1: StateT[Id,Int,Unit] = modify[Int](1+)
val p2: StateT[Id,String,Unit] = modify[String](_ + "1")
val p3: StateT[({type l[a]=StateT[Id,String,a]})#l,Int,Unit] = p2.liftM[IST]
但是那些甚至还没有关闭,甚至可能是我所能说的全部倒退。
当然我可以这样做:
import scalaz.Lens._
val test3 = for {
_ <- firstLens[Int,String] lifts (modify (1+))
_ <- secondLens[Int,String] lifts (modify (_ + "1"))
a <- firstLens[Int,String] lifts get
b <- secondLens[Int,String] lifts get
} yield (a,b)
val go3 = test3.eval(0,"0")
但是我根本没有使用堆叠的StateT,所以它没有回答这个问题。
提前致谢!
答案 0 :(得分:10)
问题在于,您通常导入的modify
来自State
,并且无法帮助您StateT
。
从Haskell类型签名开始是一个好主意:
test3
:: (MonadState [Char] m, MonadState s (t m), MonadTrans t,
Num s) =>
t m (s, [Char])
你应该能够翻译成这样的东西:
import scalaz._, Scalaz._
def test3[M[_]: Monad](implicit
inner: MonadState[({ type T[s, a] = StateT[M, s, a] })#T, String],
outer: MonadState[
({
type T[s, a] = StateT[({ type L[y] = StateT[M, String, y] })#L, s, a ]
})#T,
Int
],
mt: MonadTrans[({ type L[f[_], a] = StateT[f, Int, a] })#L]
) = for {
_ <- outer.modify(_ + 1)
_ <- mt.liftMU(inner.modify(_ + "1"))
a <- outer.get
b <- mt.liftMU(inner.get)
} yield (a, b)
它很可怕,但它是Haskell相当简单的重写。出于某种原因,编译器似乎没有找到outer
实例,所以你必须帮助它一点:
def test3[M[_]: Monad](implicit
inner: MonadState[({ type T[s, a] = StateT[M, s, a] })#T, String],
mt: MonadTrans[({ type L[f[_], a] = StateT[f, Int, a] })#L]
) = {
val outer =
StateT.stateTMonadState[Int, ({ type L[y] = StateT[M, String, y] })#L]
for {
_ <- outer.modify(_ + 1)
_ <- mt.liftMU(inner.modify(_ + "1"))
a <- outer.get
b <- mt.liftMU(inner.get)
} yield (a, b)
}
现在您可以编写以下内容,例如:
scala> test3[Id].eval(0).eval("0")
res0: (Int, String) = (1,01)
正如Haskell示例中那样。
如果您对作为内部状态变换器的monad Id
的承诺感到满意,可以稍微清理一下(正如您的评论所示):
def test3 = {
val mt = MonadTrans[({ type L[f[_], a] = StateT[f, Int, a] })#L]
val outer = StateT.stateTMonadState[Int, ({ type L[y] = State[String, y] })#L]
for {
_ <- outer.modify(_ + 1)
_ <- mt.liftMU(modify[String](_ + "1"))
a <- outer.get
b <- mt.liftMU(get[String])
} yield (a, b)
}
它不那么通用,但它可能适合你。