2017-09-01 25 views
3

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

使用這些類型的一切的偉大工程 - 我可以利用的EitherState電源。我在錯誤的情況下短路,並可以疊加我的國一個一元組成:

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 
} 

回答

0

一些注意事項我來,所提到的方法結束後不壞:

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 DLeft(error) => failover(error).run(lockedState) 
    } 
    } yield result 
} 

可能有一天有人會糾正我的答案。