2012-01-06 14 views
15

स्काला एक Set में एक समारोह है। इसके विपरीत Seq को फ़ंक्शन के रूप में परिभाषित नहीं किया गया है।एक फ़ंक्शन सेट क्यों है?</p> <pre><code>trait Set[A] extends (A => Boolean) </code></pre> <p>इसका कारण यह है प्रकार <code>A</code> contravariant स्थिति में होता है यह असंभव एक covariant अपरिवर्तनीय <code>Set</code> के लिए करते हैं:

एक जवाब का कहना है कि गणितीय पृष्ठभूमि है इस का कारण: वहां पहले से ही सवाल क्यों सेट और seqs इस तरह से तैयार कर रहे हैं के बारे में कुछ सामग्री है । लेकिन यह जवाब थोड़ा और समझाया नहीं गया था। तो, Set को फ़ंक्शन के रूप में परिभाषित करने के लिए ठोस फायदे क्या हैं या यदि इसे अलग-अलग कार्यान्वित किया गया तो नुकसान क्या होगा?

+4

मुझे लगता है कि [यह जवाब] (http://stackoverflow.com/a/6183115/358642) आपके द्वारा लिंक किए गए पहले प्रश्न में अन्य लोगों की तुलना में बहुत अधिक है। – Philippe

+0

वैसे, अगर मैं पहले लिंक किए गए प्रश्न में फ़ू (सेट ("asd") के रूप में फ़ंक्शन 'foo' कहता हूं), तो यह संकलित करता है? – Rogach

+0

मुझे लगता है कि ऐसा इसलिए है क्योंकि ['SetFactory'] में 'लागू' विधि (https://github.com/scala/scala/blob/master/src/library/scala/collection/generic/SetFactory.scala) लचीला है विभिन्न तत्व प्रकारों के सेट तैयार करने के लिए पर्याप्त है जो सिर्फ तर्क हैं। – Philippe

उत्तर

11

प्रकार Set[A] का सेट एक तरीका है जो परीक्षण करता है यदि A प्रकार का तत्व सेट में है। इस विधि (apply) में उस तत्व का प्रतिनिधित्व करने वाले A का पैरामीटर होना चाहिए, और वह पैरामीटर contravariant स्थिति में है। इसका अर्थ है कि सेट उनके प्रकार पैरामीटर A में कॉन्वेंट नहीं हो सकते हैं। तो - यह फ़ंक्शन इंटरफ़ेस का विस्तार नहीं कर रहा है जो इसे अपरिवर्तनीय सेट को असंभव बनाता है, यह contravariant apply विधि का अस्तित्व है।

और सुविधा के कारणों के लिए, Function1 इंटरफ़ेस को विस्तारित करने के लिए समझ में आता है ताकि वे सेट को पास कर सकें और उन्हें कार्य के रूप में व्यवहार कर सकें।

इसके विपरीत, अनुक्रम अबास्ट्रक्शन में कोई विधि नहीं है जो एक तत्व अनुक्रम में है या नहीं, इसकी केवल अनुक्रमण विधि है - apply एक पूर्णांक अनुक्रमणिका लेता है, और उस अनुक्रमणिका में तत्व देता है। अनुक्रमों को कार्यों के रूप में भी परिभाषित किया जाता है, लेकिन Int => A (जो A में कॉन्वर्सेट हैं) के कार्य, A => Boolean सेट के रूप में नहीं हैं।

यदि आप अपने प्रकार के पैरामीटर A में कॉन्विएन्ट के रूप में परिभाषित किए गए थे, तो सुरक्षा को तोड़ने के तरीके के बारे में और जानना चाहते हैं, इस उदाहरण को देखें जिसमें सेट कार्यान्वयन लुकअप को कैशिंग करने के कारणों के लिए निजी सदस्यों को कुछ लिखता है (

import annotation.unchecked.{uncheckedVariance => uV} 

trait Set[+A] { 
    def apply(elem: A @uV): Boolean 
} 

class CachingSet[+A >: Null] extends Set[A] { 
    private var lastLookup: (A @uV, Boolean) = (null, false) 
    private def expensiveLookup(elem: A @uV) = (elem, true) 
    def apply(elem: A @uV): Boolean = { 
    if (elem != lastLookup._1) lastLookup = expensiveLookup(elem) 
    lastLookup._2 
    } 
    def lastQueriedElement: A = lastLookup._1 
} 

object Main extends App { 
    val css = new CachingSet[String] 
    val csa: CachingSet[AnyRef] = css 

    csa.apply(new AnyRef) 
    val s: String = css.lastQueriedElement // you'll get a ClassCastException here 
} 
6

विपरीत Seq में एक समारोह के रूप में परिभाषित नहीं है: @uV नीचे एनोटेशन जो विचरण जाँच अक्षम करता है और expensiveLookup एक computationally महंगा जांच के लिए एक कॉल अनुकरण करने के लिए अगर एक तत्व सेट में है का मतलब है) है।

सत्य नहीं है।

Seq[T] extends (Int) => T 
+0

यह आश्चर्यजनक है।मैंने यह नहीं देखा कि टाइप पैरामीटर contravariant स्थिति में नहीं होता है। अच्छा विवरण! – sschaef

+0

आप सही हैं, वे आंशिक कार्य का विस्तार करते हैं। मैंने इसे सही कर दिया है। – axel22

संबंधित मुद्दे