在斯卡拉堆积StateT [英] stacking StateT in scalaz

查看:137
本文介绍了在斯卡拉堆积StateT的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图通过从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示例完全一样。

脚注



如果您满意于将 Id 作为内部状态转换器的monad(如您的评论所示),那么可以清理一下:

  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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆