我试图在"scalaz-core"%"7.2.14"
StateT monads的组合中创建某种failover
行为。StateT [或者]在斯卡拉兹故障转移
的StateT单子环绕EitherT因此这是一个单子转换:
type Error = String
type ErrOrT[T] = Error \/ T
type State[T] = StateT[ErrOrT, String, T]
使用这些类型的一切的伟大工程 - 我可以利用的Either
加State
电源。我在错误的情况下短路,并可以叠加我的国一个一元组成:
def func1: State[Int] = ???
def func2: State[Int] = ???
def func3: State[Int] = ???
val stateMonad = for {
res1 <- func1
res2 <- func2
res3 <- func3
} yield res3
此外,我想创造这样tryWithFailover
方法。它返回原来State[T]
单子或备用State[T]
单子在内部EitherT
情况下包含左:
def tryWithFailover[T](run: State[T])(failover: Error => State[T]): State[T] = ???
所以生成的链将是:
val stateMonad = for {
res1 <- func1
res2 <- tryWithFailover(func2)(err => failover)
res3 <- func3
} yield res3
如果failover
只是一个值,它不会是一个问题。我可以使用mapT/mapK
方法访问内部monad,从而能够检查结果是左还是右。在左边的情况下,我可以用fallback
值重新创建内部monad。但它不是一个价值,它本身就是一个monad,我需要像flatMapT
这样的东西。
我是否错过了一些事情,想想它会怎么做?故障转移util功能会帮助我很多,不想在明确的run
调用中断链条。
UPD:
与价值上述故障可能是这样的:
def tryWithFailover[T](run: State[T])(failover: Error => T): State[T] = {
for {
lockedState <- State(st => (st, st))
result <- run.mapT[ErrOrT, T, String] {
case [email protected] \/-(_) => ok
case -\/(error) => \/-((lockedState, failover(error)))
}
} yield result
}
UPD2:
坏实现打破整体的一元链中间run
:
def tryWithFailover[T](run: State[T])(failover: Error => State[T]): State[T] = {
for {
lockedState <- State(st => (st, st))
result <- run.mapT[ErrOrT, T, String] {
case [email protected] \/-(_) => ok
case -\/(error) => failover(error).run(lockedState)
}
} yield result
}