我通过将Haskell函数转换为Scala来学习Scala。我有一个包含StateMonad的monad变换器堆栈
type TI a = ...
使用此monad变换器堆栈的一个功能是:
fresh :: TI Int
fresh = do n <- get
put (n + 1)
return n
由于此函数仅依赖于状态monad,因此我也可以将类型更改为:
fresh :: (MonadState Int m) => m Int
这如何转换为Scala?在Scala中,我使用构成状态和身份monad的monad变换器堆栈:
type TI[A] = StateT[Id, scala.Int, A]
Scala中的新功能如下所示:
def fresh:TI[Ty] = for {
counter <- get[scala.Int]
_ <- put[scala.Int] (counter + 1)
} yield {
TyVar(counter)
}
如何在Scala中重写类型签名,使其仅取决于State monad而不是整个monad转换器堆栈?
答案 0 :(得分:4)
Scalaz还提供了MonadState
类型类,尽管Scala类型推断的局限性意味着它不那么优雅。您可以编写以下内容,例如:
import scalaz._, Scalaz._
def fresh[F[_, _]](implicit m: MonadState[F, Int]): F[Int, Int] = for {
counter <- m.get
_ <- m.put(counter + 1)
} yield counter
然后举例如下:
scala> fresh[State]
res6: scalaz.State[Int,Int] = scalaz.IndexedStateT$$anon$10@6517b62
scala> type OptionState[s, a] = StateT[Option, s, a]
defined type alias OptionState
scala> fresh[OptionState]
res7: OptionState[Int,Int] = scalaz.IndexedStateT$$anon$10@43740ba6
请注意MonadState
的第一个类型参数需要为状态和值都设置漏洞,因此如果您想使用此方法,则需要调整TI
- fresh[TI]
原封不动。