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 を用いる必要があります。