2010-12-14 18 views
7

यदि मैं उच्च आदेश फ़ंक्शन के लिए (मुझे लगता है) सही प्रकार निर्दिष्ट करता है तो ओकैमल कंपाइलर दूसरा उस फ़ंक्शन का उपयोग अस्वीकार करता है।उच्च ऑर्डर फ़ंक्शन का प्रकार

कोड

let foo():string = 
    let f: ('a -> string) -> 'a -> string = fun g v -> g v 
    in let h = string_of_int 
    in let i = string_of_float 
    in let x = f h 23 
    in let y = f i 23.0 
    in x^y 

निम्न त्रुटि संदेश

File "test.ml", line 6, characters 14-15: 
Error: This expression has type float -> string 
     but an expression was expected of type int -> string

तो f का सर्वप्रथम प्रयोग int -> string करने के लिए अपने पहले पैरामीटर के प्रकार को ठीक करने लगता है की ओर जाता है। मैं इसे समझ सकता था। लेकिन मुझे यह नहीं मिला कि f पर प्रकार प्रतिबंध को छोड़कर समस्या ठीक हो जाती है।

let foo():string = 
    let f g v = g v 
    in let h = string_of_int 
    in let i = string_of_float 
    in let x = f h 23 
    in let y = f i 23.0 
    in x^y

और आगे बढ़ f वैश्विक विस्तार के लिए समस्या है, भी ठीक करता है:

let f: ('a -> string) -> 'a -> string = fun g v -> g v 

let foo():string = 
    let h = string_of_int 
    in let i = string_of_float 
    in let x = f h 23 
    in let y = f i 23.0 
    in x^y

क्यों कि पहला उदाहरण बाद में लोगों को करना है, जबकि संकलन नहीं है कि यह कर रहा है?

+3

मैं आपके प्रश्न से चिपक गया हूं, लेकिन एक टिप्पणी जो मैं कर सकता हूं वह है कि 'च f (g:' a-> string) (v: 'a): string = gv' जो भी आप चाहते हैं वह नहीं करता है: ' दो प्रकार की टिप्पणियों में 'ए' समान नहीं है। यदि आप 'जी' और '' v' वही 'ए' के ​​साथ। –

+2

मैं इसे ओकैमल मेलिंग सूची में पोस्ट करने की अनुशंसा करता हूं। –

+0

@ पास्कल: धन्यवाद, मैंने प्रश्न – copton

उत्तर

9

मुझे एक सरल उदाहरण है कि मुद्दे को दर्शाता है का उपयोग करते हैं।

# let cons0 (x : 'a) (y : 'a list) = x :: y;; 
val cons0 : 'a -> 'a list -> 'a list = <fun> 
# let cons1 (x : 'a) (y : 'a list) = x :: y in cons1 1 [];; 
- : int list = [1] 
# let cons2 (x : 'a) (y : 'a list) = x :: y in (cons2 1 [], cons2 true []);; 
This expression has type bool but is here used with type int 
# let cons3 x y = x :: y in (cons3 1 [], cons3 true []);; 
- : int list * bool list = ([1], [true]) 

cons0 एक बहुरूपी समारोह परिभाषा, वैश्विक क्षेत्र में परिभाषित किया गया है। यह :: ऑपरेटर के लिए बस एक छोटा सा रैपर है। अनजाने में, परिभाषा काम करता है। cons1 लगभग cons0 जैसा ही है, सिवाय इसके कि इसका दायरा in शरीर में अभिव्यक्ति तक सीमित है। गुंजाइश का परिवर्तन निर्दोष दिखता है, और निश्चित रूप से पर्याप्त है, यह टाइप चेक करता है। cons3 फिर से एक ही फ़ंक्शन है, बिना किसी प्रकार की एनोटेशन के, और हम in शरीर में इसे polymorphically उपयोग कर सकते हैं।

तो cons2 के साथ क्या गलत है? समस्या 'a का दायरा है: यह संपूर्ण अपूर्ण वाक्यांश है।मुहावरा है कि cons2 को परिभाषित करता है के शब्दों

for some type 'a, (let cons2 (x : 'a) (y : 'a list) = ... in ...) 

'a के बाद से साथ intbool (करने के लिए cons3 1 [] कारण) और के साथ (cons3 true [] के कारण, 'a का कोई संभव इन्स्टेन्शियशन है संगत होना चाहिए है। इसलिए वाक्यांश बीमार है आपके द्वारा लिखा गया।

आप अपने सामान्य प्रकार निष्कर्ष एल्गोरिथ्म के मामले में एमएल टाइपिंग के बारे में सोचना चाहते हैं, तो प्रत्येक उपयोगकर्ता की स्पष्ट अनुमति चर एकीकरण एल्गोरिथ्म में कमी का एक सेट प्रस्तुत करता है। यहाँ की कमी 'a = "type of the parameter x" और ' = "type of the parameter y" कर रहे हैं। लेकिन शंघाई सहयोग संगठन 'a का पे पूरे वाक्यांश है, यह किसी भी आंतरिक दायरे में सामान्यीकृत नहीं है। तो int और bool दोनों गैर-सामान्यीकृत 'a के लिए एकीकृत होते हैं।

हाल के संस्करण ओकैमल स्कॉप्ड प्रकार चर (जैसे Niki Yoshiuchi's answer) प्रस्तुत करते हैं।

let module M = struct 
    let cons2 (x : 'a) (y : 'a list) = x :: y 
    end in 
(M.cons2 1 [], M.cons2 true []);; 

(स्टैंडर्ड MLers ध्यान दें::। यह एक ऐसी जगह है जहां OCaml और एसएमएल अलग है)

+0

दिलचस्प बात यह है कि 'f (x: 'a)'' f x' से अलग है, क्योंकि दोनों एक ही प्रकार के हस्ताक्षर होते हैं।तथ्य यह है कि ग्लोबल स्कोप 'इन' स्कोप से अलग है, यह समझ में आता है कि यह एक सामान्य प्रकार के सामान्य जेनेरिक हल के प्रकार को एनोटेट करने वाला नहीं है। यदि व्यवहार एनोटेटेड और गैर-एनोटेटेड पैरामीटर दोनों के लिए समान था तो यह कम अजीब होगा। –

+1

@Niki: बात यह है कि, आप सामान्य रूप से इस प्रकार की टिप्पणी नहीं कर रहे हैं, आप एक चर के साथ एनोटेट कर रहे हैं। चर का दायरा संपूर्ण वाक्यांश है। मुझे लगता है कि अगर आप प्रकार चर घोषित करना चाहते हैं तो यह समस्या प्राकृतिक महसूस करेगी। (यह भी याद रखें कि वे * प्रकार * चर हैं, योजना चर नहीं टाइप करें।) – Gilles

+0

इस निर्देशक उत्तर के लिए धन्यवाद। क्या आपको याद है जब यह निर्णय लिया गया था कि 'ए' जैसे प्रकार चर के दायरे वाक्यांश थे? मुझे लगभग निश्चित है कि मुझे वर्ष 2000 के आसपास एक समय याद आया जब दायरा सिर्फ प्रकार था (उस समय, प्रश्न पर मेरी टिप्पणी वैध होगी। अब, ऐसा नहीं है, मुझे लगता है ...) –

4

यह एक वास्तविक सिर-स्क्रैचर है और अगर यह एक कंपाइलर बग है तो मुझे आश्चर्य नहीं होगा। जिसके अनुसार, आप स्पष्ट रूप से प्रकार नामकरण से आप क्या चाहते हैं कर सकते हैं: http://caml.inria.fr/pub/docs/manual-ocaml/manual021.html#htoc108

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

यह भी काम करता है:

let f g v:string = g v in 

है जो

let f (type t) (g: t->string) (v: t) = g v in 

पुस्तिका से जिस प्रकार का हस्ताक्षर आप ढूंढ रहे हैं: ('a -> string) -> 'a -> string

अजीब बात यह है कि जब आप तर्कों के प्रकार को एनोटेट करते हैं तो यह काम नहीं करता है।

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

बहुरूपी प्रकार टिप्पणियों को एक विशेष सिंटेक्स है:

let f: 'a. ('a -> string)-> 'a -> string = fun g v -> g v in 

और प्रकार बहुरूपी होना आवश्यक है: http://caml.inria.fr/pub/docs/manual-ocaml/manual021.html#toc79

+1

आपका उत्तर मुझे आश्चर्यचकित करता है कि क्या यह ओकैमल 3.12 (एक ही समय में छेड़छाड़ विधि के रूप में, बोलने के लिए) में पेश किया गया एक प्रतिगमन नहीं है। मेरे पास केवल 3.12.0 है। क्या किसी ने पुराने संस्करण के साथ प्रयास किया? –

+1

@ पास्कल क्यूओक: 3.11.2 –

+0

@ पास्कल क्यूओक के साथ 3.10.2 –

-2

एक संदर्भ बिंदु के रूप में एक ही प्रभाव पिछले संस्करणों में एक स्थानीय मॉड्यूल (≥2.0) के साथ प्राप्त किया जा सकता था , समकक्ष एफ #

let foo():string = 
    let f: ('a -> string) -> 'a -> string = fun g v -> g v 
    let h = string 
    let i = string 
    let x = f h 23 
    let y = f i 23.0 
    x^y 

संकलित करता है।

+0

कोई ऐसा उम्मीद करेगा, चूंकि 'h' और' i' दोनों F # में समान टोपी टाइप किए गए फ़ंक्शन हैं, है ना? – Chuck

+0

नहीं, चूंकि वे 'इनलाइन' नहीं हैं, इसलिए टाइप अनुमान प्रत्येक उपयोग के आधार पर एक मोनोमोर्फिक प्रकार का अनुमान लगाता है। तो 'h'' int -> स्ट्रिंग' है और 'i'' float -> string' है। (आप इसे और अधिक स्पष्ट बनाने के लिए हमेशा स्पष्ट प्रकार या लैम्ब्डा जोड़ सकते हैं।) केवल 'इनलाइन' में टोपी प्रकार हो सकते हैं; इनलाइन संदर्भ के बाहर उनका उपयोग करें, और उन्हें उपयोग के आधार पर 'सामान्य' प्रकार की तत्कालताएं प्राप्त करनी होंगी। – Brian

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