Scala:使用StateT monad转换器组成的选项的错误推断类型

时间:2013-04-28 22:39:13

标签: scala haskell monads scalaz monad-transformers

我对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] monadic值的类型为StateT[Id, String, String]而不是StateT[Option, String, String]。为什么呢?

我正在使用Scala 2.10.1,scalaz 7.0.0。

1 个答案:

答案 0 :(得分:8)

在您的示例中,对get[String]的调用是调用get的{​​{1}}方法,在此处转载:

StateFunctions

其中def get[S]: State[S, S] = init State[S, A]的别名,StateT[Id, S, A]IndexedStateT[Id, S, S, A]的别名。

由于您使用的是StateT,因此您需要在getStateTMonadState[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。