कॉम्प्रिहेंशन के लिए स्केल पर मिसमैच टाइप करें


81

यह निर्माण स्केल में एक प्रकार की बेमेल त्रुटि का कारण क्यों बनता है?

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)

यदि मैं सूची के साथ कुछ स्विच करता हूँ तो यह ठीक संकलन करता है:

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)

2
आपको किस परिणाम की उम्मीद थी कि स्काला असफल उदाहरण में वापस आएगी।
डैनियल सी। सोबरल

1
जब मैं इसे लिख रहा था तो मुझे लगा कि मुझे एक विकल्प मिलेगा [सूची [(इंट, इंट)]]।
फेलिप कामाकुरा

जवाबों:


117

समझ के लिए कॉल को विधि 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, समझ की आवश्यकता का परिणाम निश्चित रूप से होगा List। (यह मेरे लिए नया था: समझ के लिए हमेशा धाराओं में परिणाम नहीं होता है, जरूरी नहीं कि Seqएस में भी ।)

अब, कैसे 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, जैसा कि अक्सर माना जाता है।


31

समझने के लिए एक आसान टिप, समझ के लिए , इस मामले में पहले जनरेटर के विकल्प के प्रकार को वापस करने की कोशिश करेंगे, विकल्प [इंट]। इसलिए, यदि आप कुछ (1) से शुरू करते हैं, तो आपको विकल्प [टी] के परिणाम की उम्मीद करनी चाहिए।

यदि आप सूची प्रकार का परिणाम चाहते हैं , तो आपको सूची जनरेटर के साथ शुरू करना चाहिए।

यह प्रतिबंध क्यों है और यह न मानें कि आप हमेशा किसी प्रकार का अनुक्रम चाहते हैं? आपके पास एक ऐसी स्थिति हो सकती है जहां यह वापसी के लिए समझ में आता है Option। हो सकता है कि आपके पास एक Option[Int]ऐसा हो, जिसे आप किसी चीज़ के साथ मिलाना चाहते हों Option[List[Int]], जो निम्न कार्य के साथ कहे (i:Int) => if (i > 0) List.range(0, i) else None:; आप तब इसे लिख सकते थे और कोई नहीं मिलता जब चीजें "समझ में नहीं आतीं":

val f = (i:Int) => if (i > 0) Some(List.range(0, i)) else None
for (i <- Some(5); j <- f(i)) yield j
// returns: Option[List[Int]] = Some(List(0, 1, 2, 3, 4))
for (i <- None; j <- f(i)) yield j
// returns: Option[List[Int]] = None
for (i <- Some(-3); j <- f(i)) yield j
// returns:  Option[List[Int]] = None

सामान्य मामले में समझ का विस्तार कैसे किया जाता है, वास्तव में एक सामान्य प्रकार के ऑब्जेक्ट को टाइप करने के लिए M[T]फ़ंक्शन के साथ एक ऑब्जेक्ट को संयोजित करने के लिए एक सामान्य सामान्य तंत्र है । आपके उदाहरण में, एम विकल्प या सूची हो सकता है। सामान्य तौर पर इसे एक ही प्रकार का होना चाहिए । तो आप सूची के साथ विकल्प गठबंधन नहीं कर सकते। अन्य चीजों के उदाहरणों के लिए , जो इस विशेषता के उपवर्गों को देख सकते हैं ।(T) => M[U]M[U]MM

जब आपने सूची के List[T]साथ (T) => Option[T]काम शुरू किया था तब संयोजन के साथ काम क्यों किया ? इस मामले में पुस्तकालय अधिक सामान्य प्रकार का उपयोग करता है जहां यह समझ में आता है। इसलिए आप सूची को ट्रैवर्सेबल के साथ जोड़ सकते हैं और विकल्प से ट्रैवर्सेबल में एक अंतर्निहित रूपांतरण है।

लब्बोलुआब यह है: इस बारे में सोचें कि आप किस प्रकार चाहते हैं कि अभिव्यक्ति वापस लौटे और पहले जनरेटर के रूप में उस प्रकार से शुरू करें। यदि आवश्यक हो तो इसे उस प्रकार में लपेटें।


मेरा तर्क है कि नियमित forसिंटैक्स बनाने के लिए यह एक बुरा डिज़ाइन विकल्प है कि इस प्रकार के फ़ंक्शंस / मोनैडिक डिसुगरिंग करें। फ़नकार / मोनाड मैपिंग, जैसे fmap, इत्यादि के लिए अलग-अलग तरीकों से नाम क्यों नहीं रखा गया है, और forएक बहुत ही सरल व्यवहार करने के लिए सिंटैक्स आरक्षित है जो लगभग किसी अन्य मुख्यधारा की प्रोग्रामिंग भाषा से आने वाली अपेक्षाओं से मेल खाता है?
Ely

आप एक मुख्य अनुक्रमिक कंप्यूटिंग कंट्रोल फ्लो स्टेटमेंट को बनाए बिना अलग-अलग फेम / लिफ्ट प्रकार के सामान को जेनेरिक के रूप में बना सकते हैं जो बहुत ही आश्चर्यचकित करते हैं और प्रदर्शन संबंधी जटिलताएं हैं, आदि "के लिए सब कुछ काम करता है" इसके लायक नहीं है।
Ely

4

शायद इसका विकल्प Iterable नहीं होने के साथ कुछ करना है। निहितार्थ Option.option2Iterableउस मामले को संभालेगा जहां संकलक एक Iterable होने की उम्मीद कर रहा है। मुझे उम्मीद है कि लूप वेरिएबल के प्रकार के आधार पर कंपाइलर मैजिक अलग है।


1

मुझे हमेशा यह मददगार लगा:

scala> val foo: Option[Seq[Int]] = Some(Seq(1, 2, 3, 4, 5))
foo: Option[Seq[Int]] = Some(List(1, 2, 3, 4, 5))

scala> foo.flatten
<console>:13: error: Cannot prove that Seq[Int] <:< Option[B].
   foo.flatten
       ^

scala> val bar: Seq[Seq[Int]] = Seq(Seq(1, 2, 3, 4, 5))
bar: Seq[Seq[Int]] = List(List(1, 2, 3, 4, 5))

scala> bar.flatten
res1: Seq[Int] = List(1, 2, 3, 4, 5)

scala> foo.toSeq.flatten
res2: Seq[Int] = List(1, 2, 3, 4, 5)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.