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

रिटर्न Some((1, 2))स्काला के लिए-समझ टपल अपघटन के साथ

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

रिटर्न Left((1, 2))


अब मैं समझ के लिए में tuples विघटित करना चाहते हैं।

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) जैसी चीज़ों के लिए उपयोग किया जाता है, हालांकि 6.19 के अनुसार इस मामले में इसका उपयोग नहीं किया जाना चाहिए।

यह बाद की बग SI-1336: spec requires type checking of for-comprehension to consider refutability में कैप्चर की गई है, जो सात साल (2008) के लिए खुला है।

शायद कुछ भविष्य की पीढ़ी को ठीक लगेगा।


देखें why does filter have to be defined for pattern matching in a for loop in scala?

3

यह अभिव्यक्तियों के लिए एक सीमा हो सकता है।

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

का अनुवाद

Some((1, 2)).flatMap({case(a, b) => 
    Some((3, 4)).map({case (c, d) => 
    (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) 
    }) 
}) 

मैं Either उपयोग करने की अनुशंसा नहीं करते हैं, बजाय scalaz से \/ प्रकार का उपयोग करें। http://eed3si9n.com/learning-scalaz/Either.htmlEither नहीं छोड़ा गया है और न ही दाएं झुकाव, जो एक समस्या है क्योंकि यह निर्दिष्ट नहीं करता है जहां त्रुटि या मान जाता है।

+1

'या तो' सही या बाएं झुकाव नहीं हो सकता है, लेकिन 'वामप्रोजेक्शन' और 'राइटप्रोजेक्शन' निश्चित रूप से हैं! –

+1

@PaulDraper हां, लेकिन फिर जब भी आप इसका उपयोग करना चाहते हैं तो आपको '.right' या' .left' निर्दिष्ट करना होगा। और मैं शोर के बिना अपना कोड पसंद करता हूं। – Reactormonk

4

क्योंकि के लिए जनरेटर (कोई भी, किसी भी) < - या तो "अकाट्य" फिल्टर desugared कोड (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) 
    }) 
}) 

फिल्टर जहां संकलन त्रुटि होती हैं क्योंकि सही के लिए फिल्टर विधि इस तरह दिखता है (बाएं से एक समान है):

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 
} 

जो विफल रहता है (टी 1, टी 2) या तो [ए, बी] (क्या सही विस्तार करता है) में डाला जा सकता है जहां ए कुछ भी नहीं है और बी (Int, Int) है।

आप का उपयोग करके इस के करीब कुछ प्राप्त कर सकते हैं:

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 _ => 
} 
संबंधित मुद्दे