Rightを成功とする、成功/失敗文脈におけるEitherに対する二項演算です。(Scala Tips / Either (9) - 二項演算)
ここまで「Either:AND」について「Either:AND」×「値:任意の関数で計算」、「Either:AND」×「値:Monoid」、「Either:AND」×「値:Plus」をみてきました。
また「Either:OR」について「Either:OR」×「値:任意の関数で計算」、「Either:OR」×「値:Monoid」を見てきました。
今回は、値に対する二項演算としてPlusの<+>
を考えます。Plusは「Scala Tips / Either (14) - 二項演算, AND, Plus」で説明したとおりコンテナの連結を行う型クラスと思われます。
値に対する二項演算は以下の組合せとします。
- lhs/rhsともRight
- Plusの
<+>
で計算 - lhs/rhsともLeft
- lhs側を使う
(分類の基準)
Java風
if式を使って、4つの場合を記述します。「Rightの二項演算」の所で型クラスPlusの演算子<+>
を用いて型クラスPlusの型クラスインスタンスを持つオブジェクト、つまり連結機能を持つコンテナオブジェクトの連結を行っています。
def f[M[_]: Plus, A](e1: Either[Throwable, M[A]], e2: Either[Throwable, M[A]]): Either[Throwable, M[A]] = { if (e1.isRight && e2.isRight) { Right(e1.right.get <+> e2.right.get) // Rightの二項計算 } else if (e1.isRight && e2.isLeft) { e1 } else if (e1.isLeft && e2.isRight) { e2 } else { // e1.is Left && e2.isLeft e1 // Leftの二項演算 } }
Scala風
match式を使って、4つの場合を記述します。「Rightの二項演算」の所で型クラスPlusの演算子<+>
を用いてコンテナオブジェクトの連結を行っています。
def f[M[_]: Plus, A](e1: Either[Throwable, M[A]], e2: Either[Throwable, M[A]]): Either[Throwable, M[A]] = { e1 match { case Right(e1r) => e2 match { case Right(e2r) => Right(e1r <+> e2r) // Rightの二項計算 case Left(_) => e1 } case Left(_) => e2 match { case Right(_) => e2 case Left(_) => e1 // Leftの二項演算 } } }
match式のネストが気に入らない場合は以下のようにすればネストしない方式で記述することもできます。
def f[M[_]: Plus, A](e1: Either[Throwable, M[A]], e2: Either[Throwable, M[A]]): Either[Throwable, M[A]] = { (e1, e2) match { case (Right(e1r), Right(e2r)) => Right(e1r <+> e2r) // Rightの二項計算 case (Right(_), Left(_)) => e1 case (Left(_), Right(_)) => e2 case (Left(_), Left(_)) => e1 // Leftの二項計算 } }
後者(Tuple方式)は、Tupleを導入しているのとパターンマッチングの回数が増えるので性能的には不利ですが、プログラムの見通しはよくなります。フレームワークで使う場合には性能重視で前者(ネスト方式)、アプリケーションで使う場合には可読性重視で後者(Tuple方式)という選択も考えられます。
Scala
Eitherに対するORを行うScalaらしい関数合成、Monadic演算による方式を見つけることができませんでした。Scala風で説明した方法を用いることになります。(「Scala Tips / Either (15) - 二項演算, OR」と同じです。)
Scalaz
Scalazでも、Eitherに対するORを行うScalaらしい関数合成、Monadic演算による方式を見つけることができませんでした。Scala風で説明した方法を用いることになります。
(「Scala Tips / Either (15) - 二項演算, OR」と同じです。)
ノート
型クラスPlusについては、型クラスMonoidとの違い、コンテキスト・バウンドでの指定方法という話題があります。詳しくは「Scala Tips / Either (14) - 二項演算, AND, Plus」のノートを参照してください。
演算仕様
EitherのOR
EitherのORは以下の演算になります。
lhs | rhs | 結果 | Rightの値 | Leftの値 |
---|---|---|---|---|
Right | Right | Right | 二項演算 | - |
Right | Left | Right | lhs | - |
Left | Right | Right | rhs | - |
Left | Left | Left | - | 二項演算 |
lhsとrhsの両方がLeft(失敗)でない場合は、Right(成功)となります。
値に対する二項演算
値に対する二項演算は、lhs/rhsともRightだった場合と、Leftだった場合があります。
値に対する二項演算は、以下のものが考えられます。
- lhs
- lhs側を使う
- rhs
- rhs側を使う
- f(lhs, rhs) :: 任意の関数で計算
- lhs |+| rhs :: Monoidで計算
- lhs <+> rhs :: Plusで計算
諸元
- Scala 2.9.1
- Scalaz 6.0.3
0 件のコメント:
コメントを投稿