2010-08-21 19 views
11

McCarthy's प्राथमिक एस कार्य करता है और विधेय atom, eq, car, cdr, थे consकेवल LISP प्राइमेटिव का उपयोग करके defmacro फ़ंक्शन को परिभाषित करना?

वह तो लिख वह क्या एस कार्यों कहा जाता है सक्षम करने के लिए अपने बुनियादी अंकन में जोड़ने के लिए, पर चला गया: quote, cond, lambda, label

उस आधार पर तो हम उन्हें "लिस्प पुरातन" फोन करता हूँ

कैसे (हालांकि मैं numberp तरह प्रकार विधेय के बारे में एक बहस के लिए खुला रहा हूँ) क्या आप अपनी पसंद के LISP में केवल इन प्राइमेटिव का उपयोग करके defmacro फ़ंक्शन को परिभाषित करेंगे? (योजना और क्लोजर समेत)

+1

'Defmacro' एक मैक्रो है, एक समारोह नहीं। – Svante

+0

@Svante वास्तव में नहीं: http://github.com/clojure/clojure/blob/b578c69d7480f621841ebcafdfa98e33fcb765f6/src/clj/clojure/core.clj#L370 लेकिन इसमें कुछ संदिग्ध मैक्रो-जैसे जावा अंडरपिनिंग हैं। यह थोड़ी गड़बड़ है। – Isaac

+0

@ जे जी आपके प्रश्न हमेशा बहुत मजेदार हैं!उन उत्तरों को प्यार करें जो उन्हें जवाब देने में शामिल हैं :) – Isaac

उत्तर

5

मैककार्थी की LISP मशीन जैसी मशीन पर ऐसा करने की कोशिश करने में समस्या यह है कि रनटाइम पर तर्क मूल्यांकन को रोकने का कोई तरीका नहीं है, और संकलन समय पर चीजों को बदलने का कोई तरीका नहीं है (जो मैक्रोज़ करता है : मूल रूप से संकलित होने से पहले वे कोड को पुनर्व्यवस्थित करते हैं)।

लेकिन यह हमें मैककार्थी की मशीन पर रनटाइम पर हमारे कोड को फिर से लिखने से नहीं रोकता है। यह चाल हमारे "मैक्रोज़" को भेजे गए तर्कों को उद्धृत करना है, इसलिए उनका मूल्यांकन नहीं किया जाता है।

उदाहरण के तौर पर, आइए एक ऐसे फ़ंक्शन को देखें जो हम चाहते हैं; unless। हमारे सैद्धांतिक कार्य में दो तर्क, p और q लेते हैं, और qलौटाते हैं जब तकp सत्य है। यदि p सत्य है, तो शून्य वापस करें।

कुछ उदाहरण (Clojure की वाक्य रचना में है, लेकिन यह परिवर्तन नहीं करता है कुछ भी):

(unless (= "apples" "oranges") "bacon") 
=> "bacon" 

(unless (= "pears" "pears") "bacon") 
=> nil 

तो पहली बार में हम unless एक समारोह के रूप में लिखने के लिए चाहते हो सकता है:

(defn unless [p q] 
    (cond p nil 
      true q)) 

और यह लगता है ठीक काम करने के लिए:

(unless true 6) 
=> nil 

(unless false 6) 
=> 6 

और मैककार्थी के एलआईएसपी के साथ, यह सिर्फ काम करेगा ठीक। समस्या यह है कि हमारे पास हमारे आधुनिक दिन लिस्प्स में साइड-इफेक्टलेस कोड नहीं है, इसलिए तथ्य यह है कि unless पर सभी तर्कों का मूल्यांकन किया गया है, चाहे हम उन्हें चाहते हैं या नहीं, समस्याग्रस्त है। वास्तव में, यहां तक ​​कि मैककार्थी के एलआईएसपी में भी, यह एक समस्या हो सकती है, अगर तर्कों में से एक का मूल्यांकन आयु करने के लिए किया गया था, और हम केवल इसे शायद ही कभी करना चाहते हैं। लेकिन यह विशेष रूप से साइड इफेक्ट्स के साथ एक समस्या है।

इसलिए हम अपने unless का मूल्यांकन करने और वापस जाने के qकेवल अगर p गलत है करना चाहते हैं। अगर हम q और p को फ़ंक्शन के तर्क के रूप में पास करते हैं तो हम ऐसा नहीं कर सकते हैं।

लेकिन हम उन्हें quote कर सकते हैं इससे पहले कि हम उन्हें अपने कार्य में रोक दें, उनके मूल्यांकन को रोकें। और जब हमें आवश्यकता होती है, तो हम इसका मूल्यांकन करने के लिए eval (जिसे केवल प्राथमिकता वाले प्राइमेटिव्स के साथ परिभाषित प्राइमेटिव्स के साथ परिभाषित अन्य कार्यों का उपयोग करके परिभाषित किया गया है) की शक्ति का उपयोग कर सकते हैं।

तो हमारे पास एक नया unless:

(defn unless [p q] 
    (cond (eval p) nil 
      true (eval q))) 

और हम इसे थोड़ा अलग तरीके से उपयोग करें:

(unless (quote false) (quote (println "squid!"))) 
=> "squid" nil 
(unless (quote true) (quote (println "squid!"))) 
=> nil 

और वहाँ तुम क्या उदारता से एक मैक्रो कहा जा सकता है की है।


लेकिन इस defmacro या अन्य भाषाओं में बराबर नहीं है। ऐसा इसलिए है क्योंकि मैककार्थी की मशीन पर, संकलन समय के दौरान कोड निष्पादित करने का कोई तरीका नहीं था। और यदि आप eval फ़ंक्शन के साथ अपने कोड का मूल्यांकन कर रहे थे, तो यह नहीं पता था कि "मैक्रो" फ़ंक्शन में तर्कों का मूल्यांकन न करें। पढ़ने और मूल्यांकन के बीच अब भी वही अंतर नहीं था जैसा कि अभी है, हालांकि विचार वहां था। quote की शीतलता में eval के संयोजन के साथ सूची संचालन "पुनः लिखने" की क्षमता थी, लेकिन यह अब भाषा में प्रशिक्षित नहीं था क्योंकि यह अब है (मैं इसे वाक्य रचनात्मक चीनी कहूंगा, लगभग: बस अपने तर्क उद्धृत करें, और आपको वहां एक मैक्रो सिस्टम की शक्ति मिल गई है।)

मुझे आशा है कि मैंने अपने प्राइमेटिव के साथ सभ्य defmacro को परिभाषित करने के बिना आपके प्रश्न का उत्तर दिया है। यदि आप वास्तव में यह देखना चाहते हैं, तो मैं आपको क्लोजर स्रोत में हार्ड-टू-ग्रोक source for defmacro या Google के बारे में कुछ और बताऊंगा।

2

इसे अपने सभी विवरणों में पूरी तरह से समझाते हुए इसके उत्तर के लिए एक बहुत सारी जगह और समय की आवश्यकता होगी, लेकिन रूपरेखा वास्तव में बहुत सरल है। अंततः प्रत्येक एलआईएसपी में रीड-ईवाल-प्रिंटर लूप की तरह कुछ मूल होता है, जो कुछ ऐसा कहता है जो तत्व लेता है, तत्व द्वारा तत्व, इसका अर्थ देता है, और राज्य को बदलता है - या तो स्मृति में या परिणाम छापकर।

पढ़ने हिस्सा प्रत्येक तत्व को पढ़ने पर लग रहा है और इसके साथ कुछ करता है: (?)

(cond ((atom elem)(lambda ...)) 
     ((function-p elem) (lambda ...))) 

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

तुम सच में बालों विवरण देखने, संरचना और कंप्यूटर प्रोग्राम की व्याख्या पढ़ने के लिए या Queinnec के Lisp in Small PIeces में पढ़ना चाहते हैं।

+0

SCICP मैक्रोज़ के बारे में गहराई में जाना है? मुझे पीडीएफ में त्वरित खोज के साथ उनमें ज्यादा उल्लेख नहीं मिल रहा है। – Isaac

+0

यह एक ओवरम्प्लिफिकेशन हो सकता है, लेकिन क्या आप कह रहे हैं कि अगर मैंने अपना खुद का eval फ़ंक्शन लिखा है तो मैं वहां से 80% तरीका होगा, बशर्ते मेरा eval फ़ंक्शन जानता था कि मैक्रो घोषणा क्या थी, और उस मैक्रो को बाद में कॉल क्या था । – hawkeye

+0

यदि आप मैक्रोज़ के सीएल/क्लोजर से मेल खाने के अर्थशास्त्र चाहते हैं, तो 'eval' पहले फॉर्म पर' macroexpand-all' को कॉल करेगा और फिर परिणाम को एक आदिम eval पर पास करेगा जिसे मैक्रोज़ के बारे में जानने की आवश्यकता नहीं है। मैंने इस तरह एक छोटा सा लिप लागू किया है और यह काफी अच्छी तरह से काम करता है। – Brian