2012-03-07 19 views
5

प्रकार A के तत्वों और एक अन्य प्रकार A में parametrised के साथ एक टपल को देखते हुए के बजाय सदस्य पहुँच का उपयोग करते हुए:अजीब प्रकार मेल नहीं खाता जब निकालने

trait Writer[-A] { def write(a: A): Unit } 
case class Write[A](value: A, writer: Writer[A]) 

और एक उपयोग साइट:

trait Cache { def store[A](value: A, writer: Writer[A]): Unit } 

क्यों टुपल के एक्स्ट्रेक्टर का उपयोग करके अपेक्षित कार्य के बाद:

def test1(set: Set[Write[_]], cache: Cache): Unit = 
    set.foreach { 
    case Write(value, writer) => cache.store(value, writer) 
    } 

लेकिन निम्नलिखित में विफल रहता है:

def test2(set: Set[Write[_]], cache: Cache): Unit = 
    set.foreach { write => 
    cache.store(write.value, write.writer) 
    } 

त्रुटि संदेश के साथ

found : Writer[_$1] where type _$1 
required: Writer[Any] 
      cache.store(write.value, write.writer) 
             ^

मैं दूसरा रूप (test2) ठीक से संकलित करने के लिए तय कर सकते हैं?

संपादित

ओवेन द्वारा विचारों मैं बाहर की कोशिश की से प्रस्थान करता है, तो मैं यह सब पर पैटर्न मिलान के बिना काम (जो है जो मैं पहली जगह में करना चाहता था) बना सकते हैं।

// does not work 
def test3(set: Set[Write[_]], cache: Cache): Unit = { 
    def process[A](write: Write[A]): Unit = 
    cache.store(write.value, write.writer) 

    set.foreach(process) 
} 

// _does work_ 
def test4(set: Set[Write[_]], cache: Cache): Unit = { 
    def process[A](write: Write[A]): Unit = 
    cache.store(write.value, write.writer) 

    set.foreach(w => process(w)) 
} 

फिर भी सुंदर मेरे लिए अस्पष्ट ...

उत्तर

7

-Xprint:typer साथ चल रहा है यहाँ रोशन कर रहा है: यहाँ दो और अजीब मामलों, एक काम, नहीं अन्य कर रहे हैं। test2 के साथ समस्या यह है वहाँ एक अस्तित्व प्रकार है, जो दो अलग-अलग स्थानों में दिखाई देते हैं कि: दोनों write.value और write.writer एक अस्तित्व प्रकार है, लेकिन, महत्वपूर्ण, संकलक जानने का कोई तरीका नहीं है वे ही existentially है मात्राबद्ध प्रकार चर। भले ही आप उन्हें एक ही ऑब्जेक्ट से एक्सेस करते हैं, कंपाइलर भूल जाता है कि वे एक ही स्थान से आए हैं।

जब test1 पूरी तरह से लिखा गया, जैसा कि आप देख:

def test1(set: Set[Write[_]], cache: Cache) = 
    set.foreach(((x0$1: Write[_]) => x0$1 match { 
     case (value: _$1, writer: Writer[_$1])Write[_$1]((value @ _), (writer @ _)) => 
      cache.store[_$1](value, writer) 
    })); 

प्रकार चर _$1 मानों के साथ मिलान किया जाता है। प्रकार परिवर्तनीय _$1 मिलान case के दायरे में बांधता है, इसलिए यह अब अस्तित्व में नहीं है, और स्कैला बता सकता है कि value और writer समान प्रकार पैरामीटर है।

test2 के लिए समाधान existentials का उपयोग नहीं करने के लिए है:

मुझे जवाब देने का प्रयास करते हैं

def test2(set: Set[ Write[ _ ]], cache: Cache) { 
    set.foreach { case write: Write[a] => 
     cache.store(write.value, write.writer) 
    } 
} 

संपादित करें:

def test2[A](set: Set[ Write[ A ]], cache: Cache) { 
    set.foreach { write => 
     cache.store(write.value, write.writer) 
    } 
} 

या एक मैच के साथ प्रकार चर बाध्य करने के लिए आपके द्वारा लाए गए नए प्रश्न।

कारण test3 काम नहीं करता है, यह है कि जब आप लिखते हैं:

set.foreach (प्रक्रिया)

process, जो बहुरूपी है, (दो कारणों के लिए, monomorphic किए जाने के लिए है कि मैं जानता हूँ कि का):

  1. स्कैला में कार्य पॉलिमॉर्फिक नहीं हो सकते हैं; केवल विधियां हो सकती हैं। एक विधि के रूप में परिभाषित process; जब प्रथम श्रेणी के फ़ंक्शन के रूप में उपयोग किया जाता है, तो यह एक फ़ंक्शन होता है।

  2. जिस तरह से कंपाइलर टाइप अनुमान लगाता है, वह ज्यादातर पॉलिमॉर्फिक मान ले कर उन्हें कम पॉलीमोर्फिक बनाने के लिए एक साथ एकीकृत करता है। एक विधि बहस के रूप में एक वास्तविक बहुलक मूल्य पारित करने के लिए उच्च रैंक प्रकार की आवश्यकता होगी।

    set.foreach(w => process(w)) 
    

    वास्तव में एक बहुरूपी समारोह नहीं है:

कारण यह है कि test4 काम करता है कि समारोह शाब्दिक है! यह अपने तर्क के रूप में एक exestentially योग्य प्रकार लेता है; लेकिन एक बहुलक प्रकार नहीं है। इसके बाद विधि (फ़ंक्शन नहीं) process पर कॉल किया गया है, और अस्तित्व के प्रकार चर से process के प्रकार पैरामीटर से मेल खाता है। सुंदर जंगली, आह?

तुम भी लिख सकते हैं:

set.foreach(process(_)) 

जो, एक गुमनाम समारोह बनाने, एक ही बात का मतलब है।

एक और मार्ग आप या उचित नहीं मिल सकता है हो सकता है अस्तित्व प्रकार और उपयोग प्रकार के सदस्यों को छोड़ने के लिए होगा:

trait Writable { 
    type A 
    val value: A 
    val writer: Writer[A] 
} 

case class Write[T](value: T, writer: Writer[ T ]) extends Writable { 
    type A = T 
} 

def test2(set: Set[Writable], cache: Cache) { 
    set.foreach { write => 
     cache.store(write.value, write.writer) 
    } 
} 

यहाँ स्काला को देखने के लिए कि write.value और write.writer ही प्रकार पैरामीटर है में सक्षम है क्योंकि वे एक ही रास्ता निर्भर प्रकार है।

+0

स्पष्टीकरण के लिए धन्यवाद। आपका पहला समाधान लागू नहीं है, क्योंकि प्रत्येक लेखन में एक अलग प्रकार का पैरामीटर होगा। आपका दूसरा समाधान व्यवहार्य है। –

+0

मैं अभी भी वास्तव में समझ में नहीं आता कि क्या हो रहा है। प्रश्न में मेरा संपादन देखें। यही कारण है कि मैं थोड़ा और सवाल खोलने के लिए पसंद करता हूं। –

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