List, Either, Option を for 構文で使う話しの続き(toSeq, toRight, toOption を使いこなしてますか?)

Scala for = Haskell do (Java の例外を Either で包んだ後の話し) が少し好評だったので、調子に乗ってちょいネタ。
for 構文を使うと match case のネストを避けられるけれど、じゃー、下記のように書けるのかと言うと…

for {
  a <- Some(1)
  b <- Right(2).right
} yield a

"type mismatch" と怒られるハズです。何故か?
上記を map と flatMap を使った形式に変換すると下記のようになります。*1

Some(1).flatMap(a => Right(2).right.map(b => a))

Option の flatMap の型は下記の通りであり…

def flatMap [B] (f: (A) ⇒ Option[B]) : Option[B]

Option[B] が求められている箇所に Product with Either[Nothing,Int] with Serializable を与えているので "type mismatch" で怒られます。
では、どうするかと言うと…、下記のように 型 を揃える以外に方法はありません。

for {
  a <- Some(1)
  b <- Right(2).right.toOption
} yield a

当然、下記の for 構文の値は None です。

for {
  a <- Some(1)
  b <- Left(3).right.toOption
} yield a

None ではなく、詳細なエラーの内容が必要な場合は、下記のようにします。

for {
  a <- Some(1).toRight(new Exception("None")).right
  b <- Right(2).right
} yield a

toRight には、left の値を指定します。*2
下記の for 構文の値は Left(new Exception("None")) と等価です。

for {
  a <- None.toRight(new Exception("None")).right
  b <- Right(2).right
} yield a

ちなみに、List には toRight や toOption は存在しないので、Option や RightProjection/LeftProjection の toSeq を用いる必要があります。

*1:for 構文が foreach, map, flatMap, filter の糖衣構文である話しは有名ですよね

*2:逆に、toLeft は right の値を指定します