2010-11-17 11 views
9

मैंने कार्यात्मक प्रोग्रामिंग (ओकैमल) सीखना शुरू किया, लेकिन मुझे एफपी के बारे में एक महत्वपूर्ण विषय नहीं पता है: हस्ताक्षर (मुझे यकीन नहीं है कि यह उचित नाम है)। जब मैं कुछ लिखें और ocaml साथ संकलन, मैं उदाहरण के लिए मिलती है:कार्यात्मक प्रोग्रामिंग (ओकैम) में हस्ताक्षर/प्रकार

# let inc x = x + 1 ;; 
val inc : int -> int = <fun> 

यह तुच्छ है, लेकिन मैं नहीं जानता कि क्यों इस:

val something : (’a -> ’b -> ’c) -> (’a -> ’d -> ’b) -> ’a -> ’d -> ’c = <fun> 
:

let something f g a b = f a (g a b) 

एक आउटपुट देता है

मुझे लगता है कि यह विषय आप में से कई लोगों के लिए एफपी की मूलभूत बात है, लेकिन मैं यहां मदद मांगता हूं, क्योंकि मुझे कुछ भी पर हस्ताक्षर के बारे में इंटरनेट पर नहीं मिला है ओकैमल (हास्केल में हस्ताक्षर के बारे में कुछ लेख हैं, लेकिन स्पष्टीकरण नहीं)।

तो इस विषय किसी भी तरह बच जाएगा, मैं यहाँ पोस्ट कई कार्य है, जो हस्ताक्षर मुझे उलझन में बनाया:

# let nie f a b = f b a ;; (* flip *) 
val nie : (’a -> ’b -> ’c) -> ’b -> ’a -> ’c = <fun> 

# let i f g a b = f (g a b) b ;; 
val i : (’a -> ’b -> ’c) -> (’d -> ’b -> ’a) -> ’d -> ’b -> ’c = <fun> 


# let s x y z = x z (y z) ;; 
val s : (’a -> ’b -> ’c) -> (’a -> ’b) -> ’a -> ’c = <fun> 

# let callCC f k = f (fun c d -> k c) k ;; 
val callCC : ((’a -> ’b -> ’c) -> (’a -> ’c) -> ’d) -> (’a -> ’c) -> ’d = <fun> 

और स्पष्टीकरण के लिए धन्यवाद।

+0

शब्दावली नोट (जो आपकी साहित्य खोजों में मदद कर सकता है): ओकंपल में "हस्ताक्षर" का अर्थ आमतौर पर कुछ और अर्थात् मूल अभिव्यक्तियों और मूल्यों के बजाय मॉड्यूल के लिए होता है। आप जो पूछ रहे हैं उसे कभी-कभी "टाइप हस्ताक्षर" कहा जाता है लेकिन अक्सर चर "होते हैं" या "टाइप स्कीम" होते हैं। – Gilles

उत्तर

16

अवधारणाओं आप इस प्रकार के हस्ताक्षर की समझ बनाने के लिए समझने की जरूरत है की एक जोड़ी रहे हैं और मैं नहीं जानता कि कौन सा आप पहले से ही है, इसलिए मैं अपना सर्वश्रेष्ठ करने की कोशिश की हर महत्वपूर्ण अवधारणा समझाने के लिए:

Currying

जैसा कि आप जानते हैं, यदि आपके पास foo -> bar टाइप है, तो यह foo प्रकार का तर्क लेने और bar प्रकार का परिणाम लौटने का वर्णन करता है। चूंकि -> सही साहचर्य है, प्रकार foo -> bar -> bazfoo -> (bar -> baz) रूप में ही है और इस तरह एक समारोह प्रकार foo का एक तर्क ले रहे हैं और जिसका अर्थ वापसी मान एक समारोह प्रकार bar के एक मूल्य लेने और एक लौटने है प्रकार bar -> baz के एक मूल्य, लौटने का वर्णन करता है baz प्रकार का मान।

एक समारोह my_function my_foo my_bar, जो क्योंकि समारोह आवेदन बाएं साहचर्य है, (my_function my_foo) my_bar रूप में ही है जैसे कहा जा सकता है इस तरह के, यानी यह तर्क my_foo पर लागू होता है my_function और फिर समारोह है कि तर्क करने के लिए एक परिणाम के रूप में किया जाता है पर लागू होता है my_bar

क्योंकि इसे इस तरह कहा जा सकता है, foo -> bar -> baz के एक फ़ंक्शन को अक्सर "दो तर्क लेने वाला फ़ंक्शन" कहा जाता है और मैं इस शेष उत्तर में ऐसा करूँगा।

प्रकार चर

आप let f x = x की तरह एक समारोह को परिभाषित है, यह प्रकार 'a -> 'a होगा। लेकिन 'a वास्तव में ओकैमल मानक पुस्तकालय में कहीं भी परिभाषित प्रकार नहीं है, तो यह क्या है?

' के साथ शुरू होने वाला कोई भी प्रकार एक तथाकथित प्रकार परिवर्तनीय है। किसी प्रकार का चर किसी भी संभावित प्रकार के लिए खड़ा हो सकता है। तो f के ऊपर उदाहरण में int या string या list या किसी भी चीज़ के साथ कहा जा सकता है - इससे कोई फर्क नहीं पड़ता।

इसके अलावा यदि एक ही प्रकार का चर एक बार हस्ताक्षर में एक से अधिक बार प्रकट होता है, तो यह उसी प्रकार के लिए खड़ा होगा। तो ऊपर दिए गए उदाहरण में इसका मतलब है कि f का रिटर्न प्रकार तर्क प्रकार के समान है। तो यदि f को int के साथ बुलाया जाता है, तो यह int देता है। अगर इसे string के साथ बुलाया जाता है, तो यह string और इसी तरह से लौटाता है।

तो 'a -> 'b -> 'a प्रकार का एक फ़ंक्शन किसी भी प्रकार के दो तर्क (जो पहले और दूसरे तर्क के लिए समान प्रकार नहीं हो सकता है) ले सकता है और उसी प्रकार का मान देता है जैसे कि पहले तर्क के रूप में, 'a -> 'a -> 'a एक ही प्रकार के दो तर्क लेगा।

टाइप अनुमान के बारे में एक नोट: जब तक आप स्पष्ट रूप से फ़ंक्शन को एक प्रकार का हस्ताक्षर नहीं देते, ओकैम हमेशा आपके लिए सबसे सामान्य प्रकार का अनुमान लगाएगा। इसलिए जब तक कोई फ़ंक्शन किसी भी ऑपरेशन का उपयोग नहीं करता है जो केवल किसी दिए गए प्रकार (उदाहरण के लिए +) के साथ काम करता है, तो अनुमानित प्रकार में प्रकार चर शामिल होंगे।

अब प्रकार समझाने के लिए ...

val something : ('a -> 'b -> 'c) -> ('a -> 'd -> 'b) -> 'a -> 'd -> 'c = <fun> 

इस प्रकार का हस्ताक्षर आपको बताता है कि something एक समारोह चार तर्क ले रहा है।

पहला तर्क का प्रकार 'a -> 'b -> 'c है। अर्थात। एक समारोह मनमानी और संभवतः विभिन्न प्रकार के दो तर्क लेता है और मनमाना प्रकार का मूल्य लौटाता है।

दूसरा तर्क का प्रकार 'a -> 'd -> 'b है। यह फिर से दो तर्कों के साथ एक समारोह है। यहां ध्यान देने योग्य महत्वपूर्ण बात यह है कि फ़ंक्शन के पहले तर्क में पहले फ़ंक्शन के पहले तर्क के समान प्रकार होना चाहिए और फ़ंक्शन के वापसी मूल्य में पहले फ़ंक्शन के दूसरे तर्क के समान प्रकार होना चाहिए।

तीसरा तर्क का प्रकार 'a है, जो कि दोनों कार्यों के पहले तर्कों का प्रकार भी है।

आखिरकार, चौथे तर्क का प्रकार 'd है, जो दूसरे फ़ंक्शन के दूसरे तर्क का प्रकार है।

वापसी मूल्य 'c प्रकार, यानी पहले फ़ंक्शन का रिटर्न प्रकार होगा।

+1

अच्छा लेखन-अप। मैंने तुम्हारा संस्करण देखने के बाद अपना संस्करण छोड़ दिया। करी बनाने और टाइप करने के बाद, मैं स्पष्टीकरण में संदर्भ में फेंकने वाला भी फेंक दूंगा। जैसा कि आप जानते हैं, कारण उसका पहला कार्य int -> int है क्योंकि यह + ऑपरेटर का उपयोग करने से अनुमान लगा सकता है। उनके अन्य कार्य उस तरह की जानकारी प्रदान नहीं करते हैं, इसलिए वह प्रकार चर के साथ समाप्त होता है। – xscott

+0

@xscott: धन्यवाद। ये एक अच्छा बिंदु है। मैंने उस प्रभाव को टाइप वैरिएबल सेक्शन के अंतिम पैराग्राफ के रूप में जोड़ा है। मुझे लगता है कि टाइप अनुमान के बारे में एक संपूर्ण खंड जोड़ना इस प्रश्न के दायरे से बाहर होगा। मुझे लगता है कि यहां महत्वपूर्ण बात यह समझना है कि किस प्रकार का मतलब है, न कि उनके साथ ओकंपल कैसे आता है। – sepp2k

+0

वाह, अब मुझे और पता है! धन्यवाद! लेकिन मेरे पास इस नोट के बारे में एक सवाल है: "यहां ध्यान देने योग्य महत्वपूर्ण बात यह है कि फ़ंक्शन के पहले तर्क में पहले फ़ंक्शन के पहले तर्क के समान प्रकार होना चाहिए और फ़ंक्शन के वापसी मूल्य के समान होना चाहिए पहले समारोह का दूसरा तर्क। " क्यों ज़रूरी? ऐसा क्यों करना चाहिए, अन्य नहीं? – lever7

6

यदि आप वास्तव में इस विषय में रुचि रखते हैं (और विश्वविद्यालय पुस्तकालय तक पहुंच है), तो वाडलर के उत्कृष्ट (यदि कुछ हद तक दिनांकित) "कार्यात्मक प्रोग्रामिंग का परिचय" पढ़ें। यह प्रकार के हस्ताक्षर बताता है और एक बहुत अच्छा और पठनीय तरीके से अनुमान लगाता है।

दो और संकेत: ध्यान दें कि -> तीर सही-सहयोगी है, इसलिए आप चीजों को सही ढंग से समझने में मदद करते हैं, यानी a -> b -> ca -> (b -> c) जैसा ही है। यह दूसरे संकेत से जुड़ा हुआ है: उच्च आदेश कार्य। आप

let add x y = x + y 
let inc = add 1 
तो एफपी में

तरह बातें कर सकते हैं, के एक समारोह दो संख्यात्मक पैरामीटर लेने के लिए है कि के रूप में 'जोड़ें' सोच और रिटर्न एक संख्यात्मक मान नहीं आम तौर पर करना सही बात है: यह एक ऐसा फ़ंक्शन भी हो सकता है जो एक संख्यात्मक तर्क लेता है और प्रकार num -> num के साथ फ़ंक्शन देता है।

इसे समझने से आपको प्रकार हस्ताक्षर समझने में मदद मिलेगी, लेकिन आप इसे बिना कर सकते हैं। यहां, त्वरित और आसान:

# let s x y z = x z (y z) ;; 
val s : (’a -> ’b -> ’c) -> (’a -> ’b) -> ’a -> ’c = <fun> 

दाईं ओर देखो। y को एक तर्क दिया गया है, इसलिए यह a -> b है, जहां z का प्रकार है। x दो तर्क है, जिनमें से पहले एक z दिया जाता है, तो पहले तर्क के प्रकार a रूप में अच्छी तरह हो गया है। (y z) के प्रकार, दूसरा तर्क, b है, और इसलिए x के प्रकार (a -> b -> c) है। यह आपको तुरंत s के प्रकार को कम करने की अनुमति देता है।

+0

मदद के लिए धन्यवाद :) – lever7

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