Scala中的Monad Transformer栈

4

我正在学习Scala中的单子变换器,但是我遇到了一个问题,迄今为止我发现无法解决。在我的单子变换器堆栈中,我组合了Either和State单子。然而,我无法调用属于其中一个单子的函数:

import scalaz._
import Scalaz._

object Minimal {
  type Inner[A] = EitherT[Id, String, A]
  type Outer[F[+_], A] = StateT[F,Int,A]
  type Stack[A] = Outer[Inner, A]

  def foo:Stack[Int] = for {
    n <- get[Int]
  } yield {
    2 * n
  }

  def main(args: Array[String]): Unit = {
    val x = foo.eval(8)
    println(x)
  }
}

出现以下错误信息:

[error] Minimal.scala:10: type mismatch;
[error]  found   : scalaz.IndexedStateT[scalaz.Id.Id,Int,Int,Int]
[error]  required: Minimal.Stack[Int]
[error]     (which expands to)  scalaz.IndexedStateT[Minimal.Inner,Int,Int,Int]
[error]     n <- get[Int]

如果我把单子变换器栈更改为:
type Stack[A] = State[Int,A]

该程序能够编译和运行,但是我不知道哪里出了问题。
2个回答

5
方法调用get [Int]返回一个IndexedStateT [Id,Int,Int,Int]。您的Stack [Int]扩展为IndexedStateT [Inner,Int,Int,Int],其中InnerEitherT [Id,String,A]。这有点难以理解,因此我将简化您的示例。
我们创建一个带有OptionStateT,而不是使用Inner类型别名。
type Stack[A] = StateT[Option, Int, A]
get[Int] 的赋值仍然会失败。
val x:Stack[Int] = get[Int]
//type mismatch; 
//  found : scalaz.State[Int,Int]
//    (which expands to) scalaz.IndexedStateT[scalaz.Id.Id,Int,Int,Int]
//  required: Minimal.Stack[Int] 
//    (which expands to) scalaz.IndexedStateT[Option,Int,Int,Int]

为了解决这个问题,我们需要将transformer提升到一个Option中:

lift

val x:Stack[Int] = get[Int].lift[Option]

如果你将这个例子代码翻译一下,你需要将 State 提升到一个 Inner 中,像这样。注意你需要把 Inner 的定义也改为协变的:

type Inner[+A] = EitherT[Id, String, A]
type Stack[A] = StateT[Inner, Int, A]

val x:Stack[Int] = get[Int].lift[Inner]

为了避免手动提升,您可以引入隐式转换。完整的示例代码如下:

type Inner[+A] = EitherT[Id, String, A]
type Outer[F[+_], A] = StateT[F, Int, A]
type Stack[A] = Outer[Inner, A]

implicit def liftToStack[A](x:Outer[Id, A]):Stack[A] = x.lift[Inner]

def foo: Stack[Int] = for {
  n <- get[Int]
} yield {
  2 * n
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接