5

我对 Haskell monad 转换器有点熟悉,但对 Scalaz(第 7 版)来说是新手。我从以下 Haskell 代码中进行了(我认为是)一个简单的翻译:

import Control.Monad.State

type Pass a = StateT String Maybe a

monadTest :: Pass String
monadTest = do
    s <- get
    return s

到这个 Scala 代码:

import scalaz._
import Scalaz._

object StateTest {
  type Pass[A] = StateT[Option, String, A]

  def monadTest: Pass[String] =
    for {
      s <- get[String]
    } yield s
}

Haskell 代码编译。Scala 无法编译,出现以下错误:

[error] .../StateTest.scala:9: type mismatch;
[error]  found   : scalaz.IndexedStateT[scalaz.Id.Id,String,String,String]
[error]  required: StateTest.Pass[String]
[error]     (which expands to)  scalaz.IndexedStateT[Option,String,String,String]
[error]       s <- get[String]
[error]         ^

首先,scalaz 似乎StateT是根据IndexedStateT. 好的。但是,似乎get[String]一元值被推断为具有 typeStateT[Id, String, String]而不是StateT[Option, String, String]. 为什么?

我正在使用 Scala 2.10.1、scalaz 7.0.0。

4

1 回答 1

8

在您的示例中,调用get[String]是调用 的get方法StateFunctions,在此处复制:

def get[S]: State[S, S] = init

WhereState[S, A]是别名,StateT[Id, S, A]其别名是IndexedStateT[Id, S, S, A].

因为您正在使用StateT,所以您需要调用, 或在您的情况下get的实例。工作示例是:StateTMonadState[S, F]StateTMonadState[String, Option]

import scalaz._
import Scalaz._

object StateTest {
  type Pass[A] = StateT[Option, String, A]

  val sm = StateT.stateTMonadState[String, Option]

  def monadTest: Pass[String] =
    for {
      s <- sm.get
    } yield s
}

MonadState实例也可以通过隐式解析,MonadState[F[_, _], S]但由于需要 lambda 类型,使用起来不太方便。有关更多信息,请参阅 MonadState.scala 和 StateT.scala。

于 2013-04-28T23:27:01.007 回答