对返回Eithers和EitherTs的函数执行'orElse'操作

时间:2014-02-21 23:48:29

标签: scala functional-programming monads scalaz

在Scala / Scalaz中链接Either\/类型相当容易,以便从左侧“失败”值中恢复。

如何为函数(T1, T2) => Future[A \/ B]获取相同的行为?

我已经能够在两个不同的方向上解决这个问题,但无法将解决方案结合起来。

通过简单地将Scalaz的Future[A \/ B]用作EitherTtype FutureEither[A, B] = EitherT[Future, A, B]的monad实例来链接Future很容易。

我已经能够使用(T1, T2) => A \/ B链接EitherT类型:

  implicit def wrapTransform[T1, T2, A, B](f: Function2[T1, T2, A \/ B]) = EitherT[({ type λ[α] = Function2[T1, T2, α] })#λ, A, B](f)
  implicit def unwrapTransform[T1, T2, A, B](e: EitherT[({ type λ[α] = Function2[T1, T2, α] })#λ, A, B]): Function2[T1, T2, A \/ B] = e.run

  // some dummy functions
  def times2(fail: Boolean, v: Int): String \/ Int = if (fail) "times2:FAILED".left else (v * 2).right
  def fail(v1: Boolean, v: Int): String \/ Int = "fail:FAILED".left
  def alwaysPlus1(ignore: Boolean, v: Int): String \/ Int =  (v + 1).right

  val times2_times2 = (times2 _) orElse (times2 _)
  val alwaysPlus1_times2 = (alwaysPlus1 _) orElse (times2 _)

  Console println times2_times2(false, 10) // prints '\/-(20)'
  Console println times2_times2(true, 10) // prints '-\/(times2:FAILED)'
  Console println alwaysPlus1_times2(false, 10) // prints '\/-(11)''
  Console println alwaysPlus1_times2(true, 10) // prints '\/-(11)'

如何编写适用于(T1, T2) => Future[A \/ B]类型的两级嵌套的转换器?

我对函数式编程的了解仍在进行中,所以我为措辞不当和术语用法道歉。

1 个答案:

答案 0 :(得分:0)

如果你有例如Option代替Future,您可以在堆栈中添加图层:

def wrap[T1, T2, A, B](f: (T1, T2) => Option[A \/ B]) = EitherT[
  ({ type L1[a] = OptionT[
    ({ type L2[b] = (T1, T2) => b })#L2, a
  ] })#L1, A, B
](OptionT[({ type L2[b] = (T1, T2) => b })#L2, A \/ B](f))

这是一团糟,但你可以相当机械地填写类型,因为你只是从内到外 - 例如。我们的(T1, T2) => Option[A \/ _]变为EitherT[OptionT[(T1, T2) => _, _], A, _]

问题在于,如果您想使用Future执行此操作,则需要FutureT,并且一致意见是,因为它是not possible to write FutureT without blockingit's better not to provide it