在Either类型的左侧创建一个联合

时间:2016-10-03 13:27:59

标签: scala functional-programming monads scalaz category-theory

是否有办法将Either[L1, R1]的值绑定到类型为R1 => Either[L2, R2]的函数并获取值Either[L1 | L2, R2],以便各个函数可以声明并可能返回其错误和消费者这些函数的monadic管道能够以详尽,类型安全的方式清晰地处理所有可能的错误吗?

修改

这是一个例子......

sealed trait IncrementError
case object MaximumValueReached extends IncrementError

def increment(n: Int): Either[IncrementError, Int] = n match {
  case Integer.MAX_VALUE => Left(MaximumValueReached)
  case n => Right(n + 1)
}

sealed trait DecrementError
case object MinimumValueReached extends DecrementError

def decrement(n: Int): Either[DecrementError, Int] = n match {
  case Integer.MIN_VALUE => Left(MinimumValueReached)
  case n => Right(n - 1)
}

for {
  n <- increment(0).right
  n <- decrement(n).right
} yield n // scala.util.Either[Object, Int] = Right(0)

使用该返回类型,我无法进行详尽的错误处理。我很好奇是否存在使用标准Scala Either或者像scalaz这样的库中存在支持此行为的内容的方法。我希望能够处理这样的错误......

val n = for {
  n <- increment(0).right
  n <- decrement(n).right
} yield n // scala.util.Either[IncrementError | DecrementError, Int]

match n {
  case Left(MaximumValueReached) => println("Maximum value reached!")
  case Left(MinimumValueReached) => println("Minimum value reached!")
  case Right(_) => println("Success!")
}

1 个答案:

答案 0 :(得分:0)

我会这样做:

/**
  * Created by alex on 10/3/16.
  */
object Temp{
  sealed trait IncrementError
  case object MaximumValueReached extends IncrementError
  sealed trait DecrementError
  case object MinimumValueReached extends DecrementError

  type MyResult = Either[Either[IncrementError, DecrementError], Int]

  def increment(n: Int): MyResult = n match {
    case Integer.MAX_VALUE => Left(Left(MaximumValueReached))
    case n => Right(n + 1)
  }

  def decrement(n: Int): MyResult = n match {
    case Integer.MIN_VALUE => Left(Right(MinimumValueReached))
    case n => Right(n - 1)
  }

  def main(args:Array[String]) = {
    val result = for {
      k <- increment(0).right
      n <- decrement(k).right
    } yield n

    result match {
      case Left(Left(MaximumValueReached)) => println("Maximum value reached!")
      case Left(Right(MinimumValueReached)) => println("Minimum value reached!")
      case Right(_) => println("Success!")
    }
  }
}

老实说,我不喜欢它,但如果你不想让IncrementErrorDecrementError因某些原因继承某些祖先特征,那么它适用于这种情况。