Scala中的Monad转换器栈

Scala中的Monad转换器栈,scala,stack,state,monads,either,Scala,Stack,State,Monads,Either,我正在学习Scala中的monad变形金刚,但我遇到了一个至今无法解决的问题。在我的monad transformer堆栈中,我编写了非此即彼和状态monad。但是,我无法调用属于两个monad之一的函数: import scalaz._ import Scalaz._ object Minimal { type Inner[A] = EitherT[Id, String, A] type Outer[F[+_], A] = StateT[F,Int,A] type Stack[A

我正在学习Scala中的monad变形金刚,但我遇到了一个至今无法解决的问题。在我的monad transformer堆栈中,我编写了非此即彼和状态monad。但是,我无法调用属于两个monad之一的函数:

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)
  }
}

程序编译和运行没有问题。有人知道我做错了什么吗?

方法调用
get[Int]
返回一个
IndexedStateT[Id,Int,Int,Int]
。您的
Stack[Int]
扩展为
IndexedStateT[Inner,Int,Int,Int]
其中
Inner
是一个
EitherT[Id,String,A]
。这有点难以解释,所以我将简化您的示例

我们创建了一个带有
选项的
StateT
,而不是
内部的
类型别名

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]
为了解决此问题,我们需要将变压器提升到一个
选项

val x:Stack[Int] = get[Int].lift[Option]
如果将其转换为示例代码,则需要将
状态提升为
内部
,如下所示。请注意,您还需要将
内部
的定义更改为协变:

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
}
type Inner[+A]=EitherT[Id,String,A]
键入外部[F[+],A]=StateT[F,Int,A]
类型堆栈[A]=外部[内部,A]
隐式def liftToStack[A](x:Outer[Id,A]):Stack[A]=x.lift[Inner]
def foo:Stack[Int]=用于{

n我开始写这篇文章作为对的答案的评论(我刚刚投了更高的票,除了最后的隐式转换之外,我还推荐了它),但是它有点笨拙,所以这里有一个新的答案

EECOLOR的诊断完全正确,但是
MonadState
(我今天早上使用过)可以避免显式提升。例如,您可以编写以下内容:

import scalaz._, Scalaz._

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

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

如果您想捕获堆栈中的状态类型。

我不知道MonadState。太棒了!谢谢分享。
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
}
import scalaz._, Scalaz._

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

def foo: Stack[Int, Int] = for {
  n <- MonadState[Stack, Int].get
} yield 2 * n
type MyState[S, +A] = StateT[Inner, S, A]
type Stack[+A] = MyState[Int, A]