14

Option を使用して値の定義を使用して for を作成すると、期待どおりに機能します。

scala> for (a <- Some(4); b <- Some(5); val p = a * b) yield p
res0: Option[Int] = Some(20)

値の定義がない場合、Either で同じことを行うと機能します。

scala> for (a <- Right(4).right; b <- Right(5).right) yield a * b
res1: Either[Nothing,Int] = Right(20)

しかし、値の定義を使用すると、scala は for 内包の間違ったコンテナー タイプを推測するようです。

scala> for (a <- Right(4).right; b <- Right(5).right; val p = a * b) yield p
<console>:8: error: value map is not a member of Product with Serializable with Either[Nothing,(Int, Int)]
for (a <- Right(4).right; b <- Right(5).right; val p = a * b) yield p
                            ^

なぜこれを行うのですか?この動作を回避する方法は何ですか?

4

1 に答える 1

19

val p = a*b あなたがより単純なものを書くならば、問題はから来ます

for(a <-Right(4).right; b <-Right(5).right)yield a * b

コンパイルすると、適切な結果が得られます。

あなたの問題には2つの原因があります

まず、EitherプロジェクションmapflatMapには通常のシグネチャがありません。つまり、ジェネリッククラスで定義されたルーチンmapとflatMapのM[A]場合、(A => B) => M[B]および(A => M[B]) => M[B]です。M[A]ルーチンはで定義されていますEither[A,B].RightProjectionが、結果と引数ではEither[A,B]、射影はありません。

第二に、val p = a*b理解のための方法が翻訳されます。Scalaリファレンス、6.19 p 90:

ジェネレータp<-eの後に値定義p'=e'が続くと、値のペアの次のジェネレータに変換されます。ここで、xとx'は新しい名前です。

(p,p′) <- for(x@p<-e) yield {val x′@p′ = e′; (x,x′)}

を削除して、コードを少し単純化してみましょうa <-。また、名前bp変更しppp書き換えルールに近づけるために、ppforを使用しp'ます。a(p <-Right(5).right; val pp = a * p)yieldppのスコープ内にあると想定されます

ルールに従って、ジェネレーター+定義を置き換える必要があります。その周りにあるもの、for(そして)yield pp、変更されていません。

for((p, pp) <- for(x@p <- Right(5).right) yield{val xx@pp = a*p; (x,xx)}) yield pp

の内側は単純な地図に書き直されます

for((p, pp) <- Right(5).right.map{case x@p => val xx@pp = a*p; (x,xx)}) yield pp

ここに問題があります。はRight(5).right.map(...)タイプEither[Nothing, (Int,Int)]でありEither.RightProjection[Nothing, (Int,Int)]、私たちが望むものではありません。の外側では機能しません(これもに変換されmapます。にmapメソッドはありません。Eitherプロジェクションでのみ定義されます。

エラーメッセージをよく見ると、とが記載されていてもProductSerializableそれはであり、Either[Nothing, (Int, Int)]マップが定義されていないことを示しています。このペア(Int, Int)は、書き換えルールから直接取得されます。

forの理解は、適切な署名を尊重するときにうまく機能することを目的としています。プロジェクションのトリックEither(これにも利点があります)を使用すると、この問題が発生します。

于 2011-09-02T23:15:37.913 に答える