8

Iterable[Either[Throwable, String]] を、Either[Throwable, Iterable[String]] に減らす必要があります。この操作がかなり一般的かどうかはわかりませんが、 Iterable トレイトには何も見つかりませんでした。だから私はこの関数を書いた:

def reduce[A, B](xs: Iterable[Either[A, B]]): Either[A, Iterable[B]] = 
  xs.collectFirst {
    case Left(x) => x
  } match {
    case Some(x) => Left(x)
    case None => Right(xs.collect{case Right(y)=> y})
  }

これがそうでない場合、誰かがより良い方法を見つけるのを手伝ってくれますか?

4

3 に答える 3

11

この操作はシーケンシングと呼ばれることが多く、一部の関数型言語(Haskellなど)の標準ライブラリで利用できます。Scalaでは、独自のライブラリを実装することも、 Scalazのような外部ライブラリを使用することもできます。たとえば、次のようなものがあるとします。

val xs: List[Either[String, Int]] = List(Right(1), Right(2))
val ys: List[Either[String, Int]] = List(Right(1), Left("1st!"), Left("2nd!"))

これで、(Scalaz 7を使用して)次のように書くことができます。

scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._

scala> xs.sequenceU
res0: Either[String,List[Int]] = Right(List(1, 2))

scala> ys.sequenceU
res1: Either[String,List[Int]] = Left(1st!)

望んだ通りに。


ちなみに、この操作では、外側のコンテナがトラバース可能であり、内側のコンテナがアプリケーションファンクタである必要があります。Scalazは、これらの要件に非常によく似ており、これらの要件にも適合するValidationNELクラスも提供しますが、sのリストで使用すると、最初で停止するのではなく、複数のエラーが収集されます。EithersequenceValidationNEL

val zs: List[ValidationNEL[String, Int]] =
  List(1.successNel, "1st".failNel, "2nd".failNel)

今、私たちは得る:

scala> print(zs.sequenceU)
Failure(NonEmptyList(1st, 2nd))

s、sなどのsequenceリストで使用することもできます。OptionPromise

于 2012-10-28T21:48:57.363 に答える
4

明示的な return が気に入らず、コードをいくらか短縮しながらパターン マッチングを削除したい場合は、別のバージョンを次に示します。

def reduce[A, B](xs: Iterable[Either[A, B]]): Either[A, Iterable[B]] =
  xs collectFirst {
    case Left(x) => Left(x)
  } getOrElse Right(xs.flatMap(_.right.toOption))
于 2012-10-28T21:43:26.463 に答える
2

私はいつもreturnステートメントが少し厄介だと思いますが、これは次のように機能します:

def reduce[A, B](xs: Iterable[Either[A, B]]): Either[A, Iterable[B]] =
  Right(xs.collect {
    case Left(x) => return Left(x)
    case Right(x) => x
  })
于 2012-10-28T21:24:24.997 に答える