我試圖在"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
}