2016-01-07 5 views
5

पर विचार करें बनाए रखने के लिए विफल रहता हैपथ निर्भर प्रकार के आसपास पासिंग निम्नलिखित निर्भर मूल्य

Error:(17, 40) type mismatch;
found : a.type (with underlying type A$A2.this.Platform#Arch)
required: p.Arch .flatMap { case (p, a) => exec(p)(a) }

त्रुटि संदेश से ऐसा प्रतीत होता है कि scalac करने में विफल रहता मान को बनाए रखें (p) जिस पर Arch इस पर निर्भर करता है और इसलिए यह प्रक्षेपण टाइप करने का विकल्प चुनता है (हालांकि मुझे यह भी सुनिश्चित नहीं है कि A$A2.this) का अर्थ है।

.flatMap(p => exec(p)(p.parseArch("arm64").get)) 

इस स्केला संकलक में एक सीमा है या शायद मैं कुछ यहाँ याद कर रहा हूँ:

क्या इसके लायक है, निम्नलिखित के साथ अंतिम पंक्ति संकलन होगा प्रतिस्थापन के लिए

?

उत्तर

4

सरल उपाय

आपका सबसे अच्छा शर्त जब पथ पर निर्भर प्रकार के साथ काम कर हमेशा के आसपास के मालिक मूल्य रखने के लिए, क्योंकि स्काला अन्यथा बहुत ही सीमित अनुमान और तर्क शक्ति है है।

Platform.parse("ios") flatMap { 
    p => p.parseArch("arm64").map(exec(p)) 
} 

यह rewritings प्रदर्शन करने के लिए आम तौर पर संभव है, हालांकि कोड अक्सर कम संक्षिप्त और सुरुचिपूर्ण हो जाएगा:

उदाहरण के लिए, अपने कोड उदाहरण के रूप में फिर से लिखा जा सकता है। एक आम अभ्यास निर्भर कार्यों और पैरामीट्रिक कक्षाओं का उपयोग करना है।

निर्भर प्रकार

अपने उदाहरण में, कोड का उपयोग करना:

Platform.parse("ios").flatMap(p => p.parseArch("arm64").map(a => (p, a))) 

टाइप Option[(Platform, Platform#Arch)], क्योंकि स्काला का अनुमान इस तथ्य है कि टपल के दूसरे तत्व पहले तत्व पर निर्भर है बनाए रखने नहीं कर सकता है। (आपको A$A2.this.Platform मिलता है क्योंकि आपने कुछ आंतरिक संदर्भ में Platform घोषित किया है।)

दूसरे शब्दों में, स्कैला का Tuple2 प्रकार निर्भर नहीं है। हम सही कर सकते हैं कि हमारे अपने वर्ग बनाकर:

case class DepPair(p: Platform)(a: p.Arch) 

हालांकि, स्काला निर्भर वर्ग हस्ताक्षर अभी तक का समर्थन नहीं करता है, और यह संकलन नहीं होंगे। val plat और val arch पर

trait Dep { 
    val plat: Platform 
    val arch: plat.Arch 
} 
Platform.parse("ios") 
    .flatMap { p => p.parseArch("arm64").map { a => 
    new Dep { val plat: p.type = p; val arch: p.Arch = a }}} 
    .flatMap { dep => exec(dep.plat)(dep.arch) } 

सूचना ascriptions, उनके बिना के रूप में, स्काला एक परिष्कृत प्रकार प्रकार-जाँच विफल कर देगा कि उसका अनुमान लगा करने की कोशिश करेंगे: इसके बजाय, हम एक विशेषता का उपयोग करने के लिए सेट करें।

हम वास्तव में स्कैला (आईएमएचओ) में क्या करना उचित है इसकी सीमा पर हैं। उदाहरण के लिए, अगर हमने trait Dep[P <: Platform] पर parametrized किया था, तो हम सभी प्रकार की समस्याओं में मिल गया होगा।विशेष रूप से:

Error:(98, 15) type mismatch; 
found : Platform => Option[Dep[p.type]] forSome { val p: Platform } 
required: Platform => Option[B] 

स्काला एक अस्तित्व समारोह प्रकार infers, लेकिन क्या हम वास्तव में चाहते हैं समारोह प्रकार के अंदर अस्तित्व मात्रा है। हम स्काला कि समझने के लिए मार्गदर्शन करने के है, और हम की तरह कुछ के साथ अंत: मालिक val चारों ओर (सरल उपाय), या जोखिम के साथ चिपके रहते हैं:

Platform.parse("ios").flatMap[Dep[p.type] forSome { val p: Platform }]{ 
    case p => p.parseArch("arm64").map{case a: p.Arch => 
     new Dep[p.type] { val plat: p.type = p; val arch = a }}} 
    .flatMap { dep => exec(dep.plat)(dep.arch) } 

अब मैं आप तय करते हैं जो तरीका सबसे अच्छा है दूँगा आपके द्वारा छोड़ी गई स्वच्छता की किसी भी भावना को खोना!

लेकिन विवेक और existentials खोने के बारे में बात कर रही है, चलो कोशिश करते हैं और एक सा आगे की जांच करते हैं ...

का उपयोग existentials (विफल)

अपने कोड में मध्यवर्ती परिणाम के समस्याग्रस्त प्रकार Option[(Platform, Platform#Arch)] था। वास्तव में यह बेहतर व्यक्त करने के लिए, एक अस्तित्व का उपयोग कर के रूप में एक तरीका है:

Option[(p.type, p.Arch) forSome {val p: Platform}] 

हम यह स्पष्ट रूप से निर्दिष्ट द्वारा स्काला मदद कर सकते हैं, तो मध्यवर्ती परिणाम इच्छित प्रकार का है:

val tmp: Option[(p.type, p.Arch) forSome {val p: Platform}] = 
    Platform.parse("ios") 
    .flatMap { case p => p.parseArch("arm64").map { a => (p, a): (p.type, p.Arch) }} 

हालांकि, अब हम स्कैला के प्रकार प्रणाली के एक बहुत ही संवेदनशील क्षेत्र को छूते हैं, और यह अक्सर समस्याओं का कारण बनता है। वास्तव में, मैं दूसरी flatMap व्यक्त करने के लिए एक तरह से नहीं मिला ...

कोशिश कर रहा tmp.flatMap { case (p, a) => exec(p)(a) } बहुत उपयोगी देता है:

Error:(30, 30) type mismatch; 
found : a.type (with underlying type p.Arch) 
required: p.Arch 

एक और परीक्षण:

tmp.flatMap { 
    (tup: (p.type, p.Arch) forSome {val p: Platform}) => exec(tup._1)(tup._2) 
} 
Error:(32, 79) type mismatch; 
found : tup._2.type (with underlying type p.Arch) 
required: tup._1.Arch 

इस पर बिंदु, मुझे लगता है कि कोई भी उचित व्यक्ति हार जाएगा - और शायद कुछ दिनों के लिए स्कैला प्रोग्रामिंग से दूर रहें ;-)

+0

इंटरस्टिंग। मुझे लगता है कि पथ-निर्भर प्रकार अभी भी स्केल में किनारों के चारों ओर काफी मोटा है। अपना जवाब पढ़ने के बाद, मैंने उन्हें टुपल्स में पास करने के लिए छोड़ दिया है ('विशेषता 'समाधान दिलचस्प है लेकिन थोड़ा भी वर्बोज़ है) और इसके बजाय नीचे दिखाए गए बाहरी गुण के संदर्भ में आंतरिक विशेषता बना दी गई है। मेरे संदेहों को मंजूरी देने के लिए धन्यवाद। –

+0

ग्रेट। ध्यान दें कि आप अपना 'वैल प्लेटफ़ॉर्म' एक 'डीफ़ प्लेटफॉर्म' बना सकते हैं, इसलिए आपको बाहरी विशेषता में अतिरिक्त पॉइंटर रखना नहीं है (स्कैला पहले ही आंतरिक लक्षणों में बाहरी लक्षणों के लिए पॉइंटर्स स्टोर करता है)। –

+0

'def' और 'val' शामिल पॉइंटर के बीच का अंतर नहीं पता था। 'Def' को समान रूप से पॉइंटर बनाने के लिए जो कुछ भी संदर्भित करता है उसे _closure_ में नहीं दिखाएगा (सुनिश्चित नहीं है कि यह स्केल में एक चीज़ है या नहीं)? शायद आप एक लिंक साझा कर सकते हैं? –

3

मैं स्केला संकलक की वर्तमान सीमा (के रूप में एल.पी. के जवाब से दिखाया गया है) स्वीकार करने के लिए सीखा है, और बदले में इस समाधान के साथ आया था:

trait Platform { 
    trait Architecture { 
    val platform: Platform.this.type = Platform.this 
    } 

    object Architecture { 
    def parse(str: String): Option[Architecture] = ??? 
    } 
} 

object Platform { 
    def parse(str: String): Option[Platform] = ??? 
} 

def main() { 
    def exec(a: Platform#Architecture) = { 
    val p = a.platform 
    ??? 
    } 

    Platform.parse("ios") 
    .flatMap(p => p.parseArch("arm64")) 
    .flatMap(a => exec(a)) 
} 

शुक्र है, भीतरी विशेषता बाहरी विशेषता का उल्लेख कर सकते स्कैला में इस तरह, p और p.Arch को पास करने की कोई आवश्यकता नहीं है, इसके बजाय प्रत्येक a: Platform#Architecture अपने p: Platform के संदर्भ में है।

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