1

我调用外部函数,作为回报有几个Either. 说我有

val a = Right("hey")
val b = Right(2)
val c = Left("oops") .....

for{
 x <- a.right
 y <- b.right
 z <- c.right
} yield(User(x,y,z))

但是说,如果z是上面的Left。然后我想给它一个默认的字符串。即通过

for{
 x <- a.right
 y <- b.right
 z <- c.right.getOrElse(Right("default String")).right
} yield(User(x,y,z))

这东西好脏。我怎样才能减少这个:c.right.getOrElse(Right("default String")).right。Doingc.right.getOrElse("default")不会作为mapon String 返回 IndexedSeq 起作用。

4

4 回答 4

4

如this thread中所建议的,可以通过Either 隐式右偏来定义简化的语法

val user = {
  implicit def rightBiasEither[A, B](e: Either[A, B]): Either.RightProjection[A,B] =
    e.right

  for {
    x <- a
    y <- b
    z <- c getOrElse (Right("default string"))
  } yield User(x, y, z)
}

您可以选择使用限制范围显式右偏的位置,如上面的示例代码中所示,或者按照惯例将转换包装在自定义对象中以随意导入。

于 2013-08-20T09:30:40.087 回答
1

您可以编写一个函数来执行此操作:

def rightOrElse[A, B](e1: Either[A, B], e2: => Either[A, B]): Either[A, B] =
  e1.right.flatMap(_ => e2)

您仍然需要调用.right结果,以使类型与您的理解相匹配。

使用Scalaz\/(析取)类型(的改进版本)更容易做到这一点Either。它不仅是右倾的,避免了通过right投影工作的需要,而且它有一个更丰富的 API,包括一个orElse方法。

val a = \/.right("hey")
val b = \/.right(2)
val c = \/.left("oops")

for {
  x <- a
  y <- b
  z <- c orElse \/.right("default String")
} yield User(x, y, z)
于 2013-08-20T08:33:25.217 回答
0

一种可能的解决方法是考虑您可以跳过对最后一个变量的理解:

val z = c.fold(Function.const("default string"), identity)

或者

val z = c.right.getOrElse("default string")

接着:

for{
 x <- a.right
 y <- b.right
} yield(User(x,y,z))
于 2013-08-20T09:02:29.427 回答
0

另一种方法是使用scala.util.Try. 简而言之,Try就像一个Either既会偏右又会强迫左型的人Throwable。如果您的左类型可以很容易地映射到的实例,Throwable那么这是一个很好的选择。

然后,您的第一个示例将转换为:

val a = Try("hey")
val b = Try(2)
val c = Try(sys.error("oops"))

for{
 x <- a
 y <- b
 z <- c
} yield(User(x,y,z))

要提供默认值,只需使用orElse

val a = Try("hey")
val b = Try(2)
val c = Try(sys.error("oops"))

for{
 x <- a
 y <- b
 z <- c.orElse(Try("default String"))
} yield(User(x,y,z))
于 2013-08-20T08:46:58.170 回答