2011-02-04 15 views
7

स्कैला कंपाइलर को वास्तव में अज्ञात कार्यों के पैरामीटर की प्रकार की जानकारी की आवश्यकता होती है?स्कैला को अज्ञात और विस्तारित कार्यों के लिए पैरामीटर प्रकारों की आवश्यकता होती है?

उदाहरण के लिए

, इस समारोह को देखते हुए:

def callOn[T,R](target: T, f: (T => R)) = f(target) 

तो मैं इसे इस तरह का उपयोग नहीं कर सकते हैं:

callOn(4, _.toString) 
    => error: missing parameter type for expanded function ((x$1) => x$1.toString) 

और मैं

callOn(4, (_: Int).toString) 

जो बल्कि बदसूरत है निर्दिष्ट करना होगा। मेरा उदाहरण क्यों काम नहीं करता है, जबकि संग्रह कक्षाओं पर मानचित्र, फ़िल्टर, फ़ोल्ड लेफ्ट इत्यादि जैसी विधि को इस स्पष्ट प्रकार की आवश्यकता नहीं लगती है?

उत्तर

14

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

chain(2)(_*10)("xxx"+_) 

तो कैसे इस अनुमानित है:

def chain[T,A,B](x: T)(fn1: T=>A)(fn2: A=>B) = fn2(fn1(x)) 

के रूप में कहा: तो निम्नलिखित परिभाषा ले? सबसे पहले, हम ब्लॉक (2) से शुरू करते हैं जिसे Int टाइप करने के लिए जाना जाता है। T पैरामीटर में कि वापस स्थानापन्न हम पाते हैं:

def chain[A,B](x: Int)(fn1: Int=>A)(fn2: A=>B) = fn2(fn1(x)) 

अगले पैरामीटर ब्लॉक (_*10), जहाँ हम अब प्लेसहोल्डर _ के प्रकार पता Int होने के लिए ... और है गुणा एक Int एक Int द्वारा एक और Int देता है । यह लौटा प्रकार के बारे में भी सच है भले ही एक अतिप्रवाह होता है; चरम छोर पर यह एक अपवाद फेंक सकता है, लेकिन अपवादों में Nothing टाइप प्रकार है जो टाइप सिस्टम में बाकी सब कुछ का उप-वर्ग है, इसलिए हम अभी भी कह सकते हैं कि Nothing एक Int है और अनुमानित प्रकार Int अभी भी मान्य है।

A साथ

अनुमान लगाया, विधि हो जाता है:

def chain[B](x: Int)(fn1: Int=>Int)(fn2: Int=>B) = fn2(fn1(x)) 

केवल B जो ("xxx"+_) से अनुमान लगाया जा सकता छोड़कर।String + Int एक String है, विधि है:

def chain(x: Int)(fn1: Int=>Int)(fn2: Int=>String): String = fn2(fn1(x)) 

वहाँ तुम्हारे पास है: विधि की वापसी प्रकार fn2 से सीधे आता है

def chain(x: Int)(fn1: Int=>Int)(fn2: Int=>String) = fn2(fn1(x)) 

के रूप में, वह भी स्पष्ट रूप से पूर्णता के लिए दिखाया जा सकता है , सभी प्रकार सुरक्षित रूप से हल किए जाते हैं, और विधि स्थिर रूप से मान्य साबित होती है।


आपके मामले में, आप अनुमान लगाया जा करने के लिए प्रकार T जरूरत है इससे पहले कि यह प्रकार T=>R से R अनुमान लगाने के लिए संभव है। ऐसा करने के लिए आप दो अलग-अलग ब्लॉक में मानकों बाहर विभाजित करना होगा, एक curried रूप में विधि लेखन:

def callOn[T,R](target: T)(f: (T => R)) = f(target) 
6

यह सवाल भी जवाब यहां दिया गया है:

Passing functions for all applicable types around

आप उम्मीद करते हैं, ... के लिए स्काला का संकलक दो बार सही प्रकार का अनुमान लगाने के लिए खाते में दोनों मापदंडों लेने के लिए। स्कैला ऐसा नहीं करता है, हालांकि - यह केवल एक पैरामीटर सूची से अगली तक जानकारी का उपयोग करता है, लेकिन एक पैरामीटर से अगले तक नहीं। इसका मतलब यह है कि पैरामीटर एफ और एक [डब्लूएस: इस मामले में लक्ष्य और एफ] स्वतंत्र रूप से विश्लेषण किया जाता है, बिना यह जानने का लाभ प्राप्त किए कि दूसरा क्या है।

ध्यान दें कि यह एक curried संस्करण के साथ काम करता है:

scala> def callOn[T,R](target: T)(f: (T => R)) = f(target) 
callOn: [T,R](target: T)(f: (T) => R)R 

scala> callOn(4)(_.toString) 
res0: java.lang.String = 4 

scala> 
+0

अपने जवाब के लिए धन्यवाद। मान लीजिए मेरे पास यह आसान मामला है: 'def callOn4 [आर] (एफ: (Int => आर)) = एफ (4) '। मैं पैरामीटर प्रकार को यहां क्यों छोड़ सकता हूं, लेकिन अगर मैं इसे 'def callOn4 (f: (int => _)) = f (4) 'के रूप में परिभाषित करता हूं? –

+1

@jpp - बस कोशिश करें और काम करें कि आपके दूसरे संस्करण में किस प्रकार का रिटर्न अनुमान लगाया जाएगा ... –

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

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