2015-09-18 7 views
6
for { 
    a <- Some(1) 
    b <- Some(2) 
} yield (a, b) 

戻りSome((1, 2))Scalaのため、理解タプル分解を伴う

for { 
    a <- Right(1).right 
    b <- Left(2).left 
} yield (a, b) 

戻り


Left((1, 2))は、今私は理解のためにタプルを分解します。

error: constructor cannot be instantiated to expected type; 
found : (T1, T2) 
required: scala.util.Either[Nothing,(Int, Int)] 
        (a, b) <- Right((1, 2)).right 

error: constructor cannot be instantiated to expected type; 
found : (T1, T2) 
required: scala.util.Either[(Int, Int),Nothing] 

なぜ、この最後の例では動作しません:

for { 
    (a, b) <- Some((1, 2)) 
    (c, d) <- Some((3, 4)) 
} yield (a, b, c, d) 

戻りSome((1, 2, 3, 4))

for { 
    (a, b) <- Right((1, 2)).right 
    (c, d) <- Left((3, 4)).left 
} yield (a, b, c, d) 

はコンパイルに失敗しますか?違いはなんですか?

+1

を参照してください[バグ](https://issues.scala-lang.org/browse/SI-5589)は、この問題について報告があります。 – emilianogc

答えて

3

あなたが使用してこれに近いものを得ることができます

SI-5589: For-comprehension on Either.RightProjection with Tuple2 extractor in generator fails to compile

withFilter()は、いくつかのドキュメントがfilter()を参照する(と呼ばれているが、それは2.8に変更されました)、これは型推論を混乱させる。

withFilter()は、​​によれば、この場合は使用しないでくださいが、for(a <- b if c)などのものに使用されます。

この後者のバグは、SI-1336: spec requires type checking of for-comprehension to consider refutabilityに記録されています。これは7年間(2008年)公開されています。

おそらく、将来の世代ではこの修正が見つかるでしょう。


why does filter have to be defined for pattern matching in a for loop in scala?

3

これは式の制限である可能性があります。

Some((1, 2)).flatMap({case(a, b) => 
    Some((3, 4)).map({case (c, d) => 
    (a, b, c, d) 
    }) 
}) 

for { 
    (a, b) <- Some((1, 2)) 
    (c, d) <- Some((3, 4)) 
} yield (a, b, c, d) 

を翻訳すると、両方の方法を動作します。 Eitherという表現では、マップ/ flatMap バージョンのみが動作します。

for { 
    (a, b) <- Right((1, 2)).right 
    (c, d) <- Left((3, 4)).left 
} yield (a, b, c, d) 


Right((1, 2)).right.flatMap({ 
    case(a, b) => Left((3, 4)).left.map({case (c, d) => 
    (a, b, c, d) 
    }) 
}) 

私は scalazから\/タイプを使用する代わりに、Eitherを使用することはお勧めしません。 http://eed3si9n.com/learning-scalaz/Either.htmlEitherは、 の左または右リーンではありません。これは、エラーまたは値のある部分が と指定されていないため問題です。

+1

'Either'は右または左に傾いていないかもしれませんが、' LeftProjection'と 'RightProjection'は確かにあります! –

+1

@PaulDraperはいですが、使用するたびに '.right'または' .left'を指定する必要があります。私はノイズのないコードを好む。 – Reactormonk

4

ためするための発電機(でも、どれ)<が - のいずれかが「動かぬ」フィルタは、その結果、脱糖コード(why does filter have to be defined for pattern matching in a for loop in scala?)に追加されない:

Right((1, 2)).right.filter { case (a, b) => true; case _ => false }.flatMap({ 
    case(a, b) => Left((3, 4)).left.filter { case (c, d) => true; case _ => false }.map({case (c, d) => 
    (a, b, c, d) 
    }) 
}) 

フィルタは、コンパイルエラーが発生した場合であります右のフィルタ方法は、このようになりますので(左1も同様です):

def filter[X](p: B => Boolean): Option[Either[X, B]] = e match { 
    case Left(_) => None 
    case Right(b) => if(p(b)) Some(Right(b)) else None 
} 

コンパイラは、次の操作を実行しようとしていることを意味している:

(T1, T2) match { 
    case Left(_) => None 
    case Right(b) => if(p(b)) Some(Right(b)) else None 
} 

(T1、T2)は、AがNothingでBが(Int、Int)の場合、[A、B](Rightが何を拡張するか)にキャストできないため失敗します。これはバグです

for { 
    a <- Right((1, 2)).right 
    b <- Left((3, 4)).left 
} yield (a, b) match { 
    case ((c, d), (e, f)) => (c, d, e, f) 
    case _ => 
} 
関連する問題