2010-12-07 11 views
18

एक नया वर्ग है कि समझ के लिए एक स्काला में इस्तेमाल किया जा सकता बनाने के लिए, ऐसा लगता है तुम सब करने की है एक नक्शे के समारोह को परिभाषित है कि:स्केल में लूप के लिए पैटर्न मिलान के लिए फ़िल्टर को क्यों परिभाषित किया जाना चाहिए?

scala> class C[T](items: T*) { 
    | def map[U](f: (T) => U) = this.items.map(f) 
    | } 
defined class C 

scala> for (x <- new C(1 -> 2, 3 -> 4)) yield x 
res0: Seq[(Int, Int)] = ArrayBuffer((1,2), (3,4)) 

लेकिन केवल छोरों के लिए आसान के लिए काम करता है कि जहां कोई <- के बाईं ओर पैटर्न मिलान। तुम वहाँ पैटर्न मैच करने की कोशिश करते हैं, तो आप एक शिकायत है कि filter विधि से परिभाषित नहीं है मिलती है:

scala> for ((k, v) <- new C(1 -> 2, 3 -> 4)) yield k -> v 
<console>:7: error: value filter is not a member of C[(Int, Int)] 
     for ((k, v) <- new C(1 -> 2, 3 -> 4)) yield k -> v 

क्यों फिल्टर यहां मिलान पैटर्न लागू करने के लिए आवश्यक है? मैंने सोचा था कि होता है स्काला सिर्फ बराबर map कॉल में ऊपर पाश अनुवाद होगा:

scala> new C(1 -> 2, 3 -> 4).map{case (k, v) => k -> v} 
res2: Seq[(Int, Int)] = ArrayBuffer((1,2), (3,4)) 

लेकिन वह ठीक से काम करने लगता है, तो पाश के लिए कुछ और ही में अनुवाद किया जाना चाहिए। इसका अनुवाद क्या है filter विधि की आवश्यकता है?

उत्तर

18

संक्षिप्त उत्तर: स्काला की विशेषताओं के अनुसार, आप उदाहरण आप दे दी है के लिए एक 'फिल्टर' विधि परिभाषित करने की जरूरत नहीं होनी चाहिए, लेकिन वहाँ एक open bug कि साधन है वर्तमान में यह आवश्यक है।

लंबा उत्तर: समझ के लिए लागू desugaring एल्गोरिदम the Scala language specification में वर्णित है। के खंड 6.19 "comprehensions के लिए और लूप्स के लिए" साथ शुरू करते हैं (मैं विनिर्देश के संस्करण 2.9 पर देख रहा हूँ):

एक पहला कदम में, हर जनरेटर पी < - ई, जहां पी अकाट्य नहीं है (§ 8.1) ई के प्रकार के लिए पी < - e.withFilter {case p => true द्वारा प्रतिस्थापित किया गया है; मामला _ => झूठा}

आपके प्रश्न का महत्वपूर्ण बिंदु यह है कि समझ में पैटर्न अभिव्यक्ति के लिए "अचूक" है या नहीं। (पैटर्न '< -' से पहले थोड़ा सा है; अभिव्यक्ति थोड़ी देर बाद है।) यदि यह "अचूक" है तो साथ फ़िल्टर को जोड़ा नहीं जाएगा, अन्यथा इसकी आवश्यकता होगी।

ठीक है, लेकिन "अचूक" का क्या अर्थ है? Spec ("अपरिवर्तनीय पैटर्न") की धारा 8.1.14 पर आगे बढ़ें। काफी बोलते हुए, अगर संकलक साबित कर सकता है कि अभिव्यक्ति से मेल खाने पर पैटर्न विफल नहीं हो सकता है तो पैटर्न अचूक है और साथ ही फ़िल्टर कॉल भी नहीं जोड़ा जाएगा।

अब आपका उदाहरण जो उम्मीद के अनुसार काम करता है वह धारा 8.1.14, एक परिवर्तनीय पैटर्न से पहले प्रकार का अपरिवर्तनीय पैटर्न है। तो पहला उदाहरण संकलक के लिए यह निर्धारित करना आसान है कि withFilter आवश्यक नहीं है।

आपका दूसरा उदाहरण संभावित रूप से तीसरा प्रकार का अपरिवर्तनीय पैटर्न, एक कन्स्ट्रक्टर पैटर्न है। के साथ Tuple2[Any,Any] से मिलान करने का प्रयास कर रहा है (Tuple2[Int,Int] के विरुद्ध (विनिर्देश से सेक्शन 8.1.6 और 8.1.7 देखें)) Int के बाद सफल होता है Any के लिए अपरिहार्य है। इसलिए दूसरा पैटर्न भी अचूक है और withFilter विधि की आवश्यकता नहीं है (नहीं)।

डैनियल के उदाहरण में, Tuple2[Any,Any]Any के विरुद्ध अपरिहार्य नहीं है, इसलिए फ़िल्टर कॉल को जोड़ा जाता है।

वैसे, त्रुटि संदेश एक filter विधि के बारे में बात करती है, लेकिन कल्पना withFilter बारे में बात करती है - यह स्काला 2.8 के साथ बदल गया था, रक्तमय जानकारी के लिए this question and answer देखते हैं।

12

अंतर देखें:

scala> for ((k, v) <- List(1 -> 2, 3 -> 4, 5)) yield k -> v 
res22: List[(Any, Any)] = List((1,2), (3,4)) 

scala> List(1 -> 2, 3 -> 4, 5).map{case (k, v) => k -> v} 
scala.MatchError: 5 
+0

मैंने संकलित कोड को '5' के साथ और बिना चेक किया। जब कोई '5' नहीं होता है, तो फ़िल्टर का उपयोग नहीं किया जाता है। – IttayD

+11

वाह, मुझे कभी एहसास नहीं हुआ कि लूप के लिए चुपचाप गैर मेल खाने वाले आइटम फेंक देंगे। यह एक सूक्ष्म गोचा की तरह लगता है मैं बेहतर देखने के लिए बाहर देखो। – Steve

+0

'मानचित्र' संस्करण लगभग खतरनाक है, क्योंकि इसमें कोई चेतावनी नहीं है कि यह फेंक सकता है। दुर्भाग्यवश, आंशिक फ़ंक्शन का उपयोग किए बिना फ़ंक्शन शाब्दिक में तर्कों को नष्ट करने के लिए वर्तमान में कोई वाक्यविन्यास नहीं है। –