2011-08-19 17 views
9

इस उदाहरण देखें:क्यों स्कैला आंशिक विधि में प्रकार का अनुमान नहीं लगा सकता है?

def hello(a:String, b:String) = println(a + ":" + b) 
val m1 = hello("aaa", _) 
m1("bbb") 

यह संकलित नहीं किया जा सकता, कि मैं आंशिक विधि के प्रकार जोड़ने की जरूरत:

val m1 = hello("aaa", _: String) 

क्यों स्केला विधि के 2 पैरामीटर पता नहीं है helloString है?

उत्तर

15

स्कैला का प्रकार अनुमान प्रवाह आधारित है। विधियों और कार्यों को स्पष्ट पैरामीटर प्रकारों की आवश्यकता होती है, जिनका उपयोग अन्य प्रकारों का अनुमान लगाने के लिए किया जाता है। पैरामीटर प्रकार विधि या फ़ंक्शन बॉडी से अनुमानित नहीं हो सकते हैं। कभी-कभी, पैरामीटर प्रकार बाहरी संदर्भ से ज्ञात होते हैं, और फिर उन्हें लेबल करने की आवश्यकता नहीं होती है। दो उदाहरणों में शामिल

val f: String => Unit = hello("aaa", _) 
val s = Seq(1,2).map(_+1) // Seq[Int].map expects a function of Int argument type 

नीचे करने के लिए, कहते हैं, एमएल और हास्केल तुलना स्काला के प्रकार निष्कर्ष की सीमाओं के बारे मार्टिन ओडर्स्की से एक उद्धरण है। चुनौतियां स्काला का अधिक भार, रिकॉर्ड चयन, और subtyping, साथ ही चीजों को सरल रखने के लिए की जरूरत है, शामिल हैं

कारण स्काला नहीं है Hindley/मिलनर प्रकार निष्कर्ष है कि यह सुविधाओं जैसे के साथ गठबंधन करने के लिए बहुत मुश्किल है है अधिभार के रूप में ( विज्ञापन-भिन्न संस्करण, वर्गों का प्रकार नहीं), रिकॉर्ड चयन, और उप प्रकार। मैं असंभव नहीं कह रहा हूं - इन सुविधाओं को शामिल करने वाले कई एक्सटेंशन मौजूद हैं; असल में मैं उनमें से कुछ खुद का गिटली रहा हूं। मैं बस इतना कह रहा हूं कि अभ्यास में यह काम अच्छी तरह से करना मुश्किल है, जहां किसी को छोटे प्रकार के भाव, और अच्छे त्रुटि संदेशों की आवश्यकता होती है। यह एक शट केस नहीं है - कई शोधकर्ता सीमाओं को धक्का देने पर काम कर रहे हैं (रेमी के एमएलएफ पर उदाहरण के लिए देखें)। लेकिन फिलहाल यह बेहतर सुविधाओं के संदर्भ में इन सुविधाओं के लिए बेहतर समर्थन का एक व्यापार है। आप दोनों तरीकों से ट्रेडऑफ बना सकते हैं। तथ्य यह है कि हम जावा के साथ एकीकृत करना चाहते थे, उपन्यास और हिंडली/मिलनर से दूर के पक्ष में स्केल को स्केल किया।

स्रोत: Universal Type Inference is a Bad Thing पोस्ट के तहत टिप्पणी।

3

ऐसा इसलिए हो सकता है क्योंकि hello के रूप में इस परिभाषा के साथ संभावित अस्पष्टता अधिभारित हो सकती है।

// inside some class context 
def hello(a:String, b:String) = println(a + ":" + b) 
def hello(a:String, b:Int) = println(a + ":" + b.toString) 
val m1 = hello("aaa", _) // which one to choose? 

ध्यान दें कि यह केवल आप ही नहीं है जो val m1 = hello("aaa", _) कर सकते हैं। आपकी कक्षा का उपयोगकर्ता हो सकता है, val my_hello = (new C).hello("aaa", _) कर रहा है। और फिर आप अपनी मूल स्ट्रिंग हैलो विधि में ओवरलोड जोड़कर स्रोत-कोड संगतता को तोड़ते हैं क्योंकि अचानक यह स्पष्ट नहीं होता है कि क्या किया जाना चाहिए।

मुझे यकीन नहीं है कि यह एकमात्र कारण है लेकिन कोई निश्चित रूप से इसे सुरक्षा उपाय के रूप में देख सकता है।

+0

लेकिन मेरे कोड में, केवल एक 'हैलो' विधि है। आपका मतलब है, कक्षा को बढ़ाया जा सकता है, और उप वर्ग 'हैलो' विधि को ओवरराइड कर सकता है, और कोड तोड़ सकता है? – Freewind

+0

मुझे स्वीकार करना होगा, मुझे यकीन नहीं है कि यह सबक्लासिंग के साथ वास्तव में संभव है या नहीं। लेकिन इसके बिना भी, मुझे लगता है कि यह हमेशा एनोटेशन प्रकार की आवश्यकता के लिए थोड़ा और संगत बनाता है। अन्यथा एक प्रकार के एनोटेशन के बिना सभी कोड जो अचानक टूट जाएंगे, अगर आपने ओवरलोड जोड़ना चुना है। – Debilski

+0

मैं उत्सुक हूं कि क्यों, उस मामले में, 'एम 1' सिर्फ तर्क के प्रकार पर बहुलक नहीं है। –

4

इसे बहुत सरलता से रखने के लिए, स्कैला उचित विधि की खोज के लिए पैरामीटर प्रकारों का उपयोग करता है, पैरामीटर के प्रकार को कम करने के लिए विधि प्रकार नहीं।

जो भी आप चाहते हैं, उसे hello पर दो पैरामीटर के साथ सभी संभावित कॉलों को खोजना होगा, उनमें से पहला String - जिसमें अंतर्निहित रूपांतरण शामिल हो सकते हैं - और फिर, यदि एक सबसे विशिष्ट विकल्प पाया जाता है , उस दूसरे पैरामीटर के प्रकार का अनुमान लगाने के लिए इसका इस्तेमाल करें। इसे को के साथ यह सब कुछ करने के लिए करना होगा, जो पहले से ही धीमा संकलन है, और भी धीमा कर रहा है। असंभव नहीं है, लेकिन ऐसा नहीं करता है।

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