简体   繁体   English

在scalaz中堆叠StateT

[英]stacking StateT in scalaz

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 我试图通过移植Dan Piponi本教程中的一些例子来了解Scala中的Monad Transformers: 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? 但是我怎么能将下一个例子移植到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: 我已经使用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. 但是我根本就没有使用堆叠的StateT,所以它没有回答这个问题。

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 . 问题是您使用常规导入进行的modify来自State ,并且不会帮助您使用StateT

It's a good idea to start with the Haskell type signature: 从Haskell类型签名开始是个好主意:

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. 它很可怕,但它是Haskell相当简单的重写。 For some reason the compiler doesn't seem to find the outer instance, though, so you have to help it a little: 出于某种原因,编译器似乎没有找到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)
}

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. 正如在Haskell示例中一样。

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): 如果您对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)
}

It's a little less generic, but it may work for you. 它不太通用,但它可能对你有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM