【问题标题】:stacking StateT in scalaz在scalaz中堆叠StateT
【发布时间】:2014-05-06 05:11:33
【问题描述】:

我试图通过移植 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")

但是我根本没有使用stacked StateT,所以它没有回答这个问题。

提前致谢!

【问题讨论】:

    标签: scala haskell scalaz monad-transformers state-monad


    【解决方案1】:

    问题是您通过通常的导入获得的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 示例中的完全一样。

    脚注

    如果您愿意将 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)
    }
    

    它不太通用,但它可能对你有用。

    【讨论】:

    • 我喜欢从 Haskell 签名开始并向后工作的想法,但我从 GHCi 7.4.2 得到这个:test3 :: StateT Integer (StateT [Char] Identity) (Integer, [Char])。我隐约明白这相当于你贴的签名,但我自己怎么去那里呢?或者从这个签名到 scalaz 等价物?
    • 例如,您可以通过在 REPL 中单独定义 test3 来查看更通用的类型。如果您仅在 go3 中使用它,它将专门针对您所看到的版本。
    • 哦,好的。鉴于 State、String 和 Int 无论如何都被硬编码到定义中,scalaz 是否也有更简单/专门的实现?还是让编译器找到其中一些实例实际上简化了代码?
    • 嘿@travis-brown -> 有什么方法可以通过导入访问StateT 的正确get/modify/put?我可以看到它们是在源代码中定义的,但是当说使用 StateT[Future, S, A] 时我看不到导入它们的方法
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-29
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多