1. ホーム
  2. scala

[解決済み] for-comprehensionでOptionとListを合成すると、順序によって型の不一致が発生する。

2023-06-06 20:27:09

質問

なぜこの構文はScalaでType Mismatchエラーを引き起こすのでしょうか?

for (first <- Some(1); second <- List(1,2,3)) yield (first,second)

<console>:6: error: type mismatch;
 found   : List[(Int, Int)]
 required: Option[?]
       for (first <- Some(1); second <- List(1,2,3)) yield (first,second)

SomeとListを入れ替えても問題なくコンパイルできます。

for (first <- List(1,2,3); second <- Some(1)) yield (first,second)
res41: List[(Int, Int)] = List((1,1), (2,1), (3,1))

これも問題なく動作します。

for (first <- Some(1); second <- Some(2)) yield (first,second)

どのように解決するのですか?

内包は map または flatMap メソッドを使用することができます。例えばこのようなものです。

for(x <- List(1) ; y <- List(1,2,3)) yield (x,y)

がそうなる。

List(1).flatMap(x => List(1,2,3).map(y => (x,y)))

したがって、最初のループ値(この場合。 List(1) ) を受け取ることになります。 flatMap メソッド呼び出しを受け取ります。そのため flatMap の上に List は別の List を返した場合、for comprehensionの結果はもちろん List . (これは私にとって新しいことでした。for内包の結果が常にストリームになるとは限りません。 Seq s.)

では、どのように flatMap がどのように宣言されているか見てみましょう。 Option :

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

このことを頭に入れておいてください。それでは、誤った内包の仕方( Some(1) のあるもの)がどのようにマップ呼び出しのシーケンスに変換されるかを見てみましょう。

Some(1).flatMap(x => List(1,2,3).map(y => (x, y)))

さて、このようにすると、パラメータである flatMap を返すものであることがわかります。 List を返しますが Option ではなく、必要な

事を解決するためには、以下のようにします。

for(x <- Some(1).toSeq ; y <- List(1,2,3)) yield (x, y)

これでうまくコンパイルできます。注目すべきは Option のサブタイプではないことに注意してください。 Seq のサブタイプではありません。