मैककार्थी की 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 के बारे में कुछ और बताऊंगा।
'Defmacro' एक मैक्रो है, एक समारोह नहीं। – Svante
@Svante वास्तव में नहीं: http://github.com/clojure/clojure/blob/b578c69d7480f621841ebcafdfa98e33fcb765f6/src/clj/clojure/core.clj#L370 लेकिन इसमें कुछ संदिग्ध मैक्रो-जैसे जावा अंडरपिनिंग हैं। यह थोड़ी गड़बड़ है। – Isaac
@ जे जी आपके प्रश्न हमेशा बहुत मजेदार हैं!उन उत्तरों को प्यार करें जो उन्हें जवाब देने में शामिल हैं :) – Isaac