2017-09-01 45 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 
} 

可能有一天有人会纠正我的答案。