在斯卡拉堆积StateT [英] stacking StateT in scalaz
问题描述
我试图通过从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 test20
变成:
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
}收益率(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] =修改[String](_ +1)
val p3:StateT [({type l [a] = StateT [Id,String,a]})#l,Int,Unit] = p2.liftM [IST ]
但这还没有结束,甚至可能会倒退。当然我可以这样做:
pre $ code $> import scalaz.Lens._
val test3 = for {
_< - firstLens [Int,String] lifts(modify(1+))
_< - secondLens [Int,String ]升降机(修改(_ +1))
a < - firstLens [Int,String]升降机获得
b< - secondLens [Int,String]升降机获得
} ,b)
val go3 = test3.eval(0,0)
预先感谢!
问题在于,通常导入的修改
来自州
,并不会帮助你 StateT
。
从Haskell类型签名开始:
s(tm),MonadTrans t,Num s)=>
tm(s,[Char])
您应该可以将其转换成类似这:
import scalaz._,Scalaz._
def test3 [M [_]: Monad](隐式
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](隐式
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示例完全一样。
脚注
如果您满意于将
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)
}
这不是一般的,但它可能适用于您。
I'm trying to understand Monad Transformers in Scala by porting some examples from this tutorial by Dan Piponi: http://blog.sigfpe.com/2006/05/grok-haskell-monad-transformers.html
I did a couple of easy ones:
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"
becomes:
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")
But how the heck can I port this next example to Scala?
test3 = do
modify (+ 1)
lift $ modify (++ "1")
a <- get
b <- lift get
return (a,b)
go3 = runIdentity $ evalStateT (evalStateT test3 0) "0"
I've gotten this far using 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]
but that's not even close yet, and may even be backwards for all I can tell.
Of course I can do this:
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")
but then I'm not using stacked StateT at all, so it doesn't answer the question.
Thanks in advance!
The problem is that the modify
you get with the usual imports is from State
, and isn't going to help you with StateT
.
It's a good idea to start with the Haskell type signature:
test3
:: (MonadState [Char] m, MonadState s (t m), MonadTrans t,
Num s) =>
t m (s, [Char])
Which you should be able to translate into something like this:
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)
It's hideous, but it's a fairly straightforward rewording of the Haskell. For some reason the compiler doesn't seem to find the outer
instance, though, so you have to help it a little:
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)
}
Now you can write the following, for example:
scala> test3[Id].eval(0).eval("0")
res0: (Int, String) = (1,01)
Exactly as in the Haskell example.
Footnote
You can clean this up a bit if you're happy with committing to Id
as the monad of the inner state transformer (as your comment suggests):
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)
}
It's a little less generic, but it may work for you.
这篇关于在斯卡拉堆积StateT的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!