use*_*840 4 monads stack state scala either
我正在学习Scala中的monad变换器,但是遇到了一个我发现到目前为止无法解决的问题.在我的monad变换器堆栈中,我组成了Either和State 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)
}
}
Run Code Online (Sandbox Code Playgroud)
失败,出现以下错误消息:
[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]
Run Code Online (Sandbox Code Playgroud)
如果我将monad变换器堆栈更改为:
type Stack[A] = State[Int,A]
Run Code Online (Sandbox Code Playgroud)
该程序编译和运行没有问题.有谁知道我在这里做错了什么?
方法调用get[Int]返回一个IndexedStateT[Id, Int, Int, Int].你Stack[Int]扩张到IndexedStateT[Inner, Int, Int, Int]哪里Inner是EitherT[Id, String, A].这有点难以理解,所以我会简化你的例子.
而不是Inner类型别名,我们创建StateT一个Option.
type Stack[A] = StateT[Option, Int, A]
Run Code Online (Sandbox Code Playgroud)
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]
Run Code Online (Sandbox Code Playgroud)
为了解决这个问题,我们需要lift将变压器改为Option:
val x:Stack[Int] = get[Int].lift[Option]
Run Code Online (Sandbox Code Playgroud)
如果你翻译,为您的示例代码,你需要lift在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]
Run Code Online (Sandbox Code Playgroud)
为了能够在不手动提升的情况下编写此内容,您可以引入隐式转换.完整的例子:
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
}
Run Code Online (Sandbox Code Playgroud)
我开始写这篇文章作为对EECOLOR答案的评论(我刚刚赞成,我推荐 - 除了最后的隐式转换),但它有点笨拙,所以这是一个新的答案.
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
Run Code Online (Sandbox Code Playgroud)
请注意(在我之前的问题中)我已经改变Stack为在状态类型上进行参数化.您可以轻松地将其更改为以下内容:
type MyState[S, +A] = StateT[Inner, S, A]
type Stack[+A] = MyState[Int, A]
Run Code Online (Sandbox Code Playgroud)
如果要捕获堆栈中的状态类型.
| 归档时间: |
|
| 查看次数: |
1190 次 |
| 最近记录: |