Ответ 1
Проблема в том, что modify
, который вы получаете с обычным импортом, находится в State
и не поможет вам с StateT
.
Хорошая идея начать с сигнатуры типа Haskell:
test3
:: (MonadState [Char] m, MonadState s (t m), MonadTrans t,
Num s) =>
t m (s, [Char])
Что вы должны перевести на что-то вроде этого:
import scalaz._, Scalaz._
def test3[M[_]: Monad](implicit
inner: MonadState[({ type T[s, a] = StateT[M, s, a] })#T, String],
outer: MonadState[
({
type T[s, a] = StateT[({ type L[y] = StateT[M, String, y] })#L, s, a ]
})#T,
Int
],
mt: MonadTrans[({ type L[f[_], a] = StateT[f, Int, a] })#L]
) = for {
_ <- outer.modify(_ + 1)
_ <- mt.liftMU(inner.modify(_ + "1"))
a <- outer.get
b <- mt.liftMU(inner.get)
} yield (a, b)
Это отвратительно, но это довольно простая перестановка Хаскелла. По какой-то причине компилятор, похоже, не находит экземпляр outer
, хотя вам нужно немного помочь:
def test3[M[_]: Monad](implicit
inner: MonadState[({ type T[s, a] = StateT[M, s, a] })#T, String],
mt: MonadTrans[({ type L[f[_], a] = StateT[f, Int, a] })#L]
) = {
val outer =
StateT.stateTMonadState[Int, ({ type L[y] = StateT[M, String, y] })#L]
for {
_ <- outer.modify(_ + 1)
_ <- mt.liftMU(inner.modify(_ + "1"))
a <- outer.get
b <- mt.liftMU(inner.get)
} yield (a, b)
}
Теперь вы можете написать следующее, например:
scala> test3[Id].eval(0).eval("0")
res0: (Int, String) = (1,01)
Точно так же, как в примере Haskell.
Сноска
Вы можете немного почистить это, если вы довольны тем, что совершили Id
в качестве монады внутреннего трансформатора состояния (как предлагает ваш комментарий):
def test3 = {
val mt = MonadTrans[({ type L[f[_], a] = StateT[f, Int, a] })#L]
val outer = StateT.stateTMonadState[Int, ({ type L[y] = State[String, y] })#L]
for {
_ <- outer.modify(_ + 1)
_ <- mt.liftMU(modify[String](_ + "1"))
a <- outer.get
b <- mt.liftMU(get[String])
} yield (a, b)
}
Это немного менее общий, но он может сработать для вас.