EitherとOptionの相互変換のイディオムです。
EitherのRightを成功、Leftを失敗として扱うことを想定しています。逆の場合は、成否の判定を反転させてください。
(分類の基準)
Java風
Option→Either
OptionをEitherに変換する場合は、OptionのifDefinedメソッドでSome(成功の文脈)の判定を行い、Someの場合はその値をRightに、そうでない場合は失敗の内容を示す値(この場合はThrowable)をLeftに詰めます。
def f[T](o: Option[T], e: Throwable): Either[Throwable, T] = { if (o.isDefined) Right(o.get) else Left(e) }
Optionでは、成功と失敗の切り分けはできますが、失敗の内容を示す値は保持していないので、外側から指定する必要があります。
Either→Option
EitherをOptionに変換する場合は、EitherのisRihtメソッドで成功(Right)であることを確認した後、rightメソッドで取得したRightProjectionのrightメソッドを用いて値を取り出し、Someに詰めます。EitherがLeftの場合は、Left側の値は捨ててNoneを返します。
def f[T](e: Either[Throwable, T]): Option[T] = { if (e.isRight) Some(e.right.get) else None }
Scala風
Option→Either
OptionをEitherに変換する場合は、match式を用いて、SomeとNoneの判定を行い、Someの場合は格納されている値をRightに詰めます。Noneの場合は、失敗を示す値をLeftに詰めます。
def f[T](o: Option[T], e: Throwable): Either[Throwable, T] = { o match { case Some(s) => Right(s) case None => Left(e) } }
Either→Option
EitherをOptionに変換する場合は、match式でLeftまたはRightを判定し、Rightの場合は取得した値をSomeに詰めます。Leftの場合は、Left側の値は捨ててNoneを返します。
def f[T](e: Either[Throwable, T]): Option[T] = { e match { case Right(s) => Some(s) case Left(_) => None } }
Scala
Option→Either
OptionをEitherに変換するMonadicな演算はないと思います。Scala風で説明したmatch式方式を用いるとよいでしょう。
Either→Option
EitherをOptionに変換する場合、Eitherのfoldメソッドを使うことができます。
def f[T](e: Either[Throwable, T]): Option[T] = { e.fold(_ => None, Some(_)) }
Scalaz
Option→Either
Scalazでは、OptionをValidationに変換するtoSuccessメソッドが追加されています。ValidationはさらにEitherに変換するeitherメソッドを持っているので、これを連結して使用します。
def f[T](o: Option[T], e: Throwable): Either[Throwable, T] = { o.toSuccess(e).either }
Either→Option
ScalazではEitherをOptionに変換する便利なメソッドは用意していません。Javaで説明したfoldメソッドを用いるとよいでしょう。
ノート
EitherとOptionの相互変換は以下の手法がよいでしょう。
- Either→Option
- Eitherのfoldメソッド (Scala)
- Option→Either
- Validation経由 (Scalaz)
性能を重視する場合はJava風、ScalaやScalazの技が思い浮かばなかった場合はScala風のmatch式が安全策です。
諸元
- Scala 2.9.1
- Scalaz 6.0.3
0 件のコメント:
コメントを投稿