2017-05-15 11 views
6

के साथ नहीं किया जा सकता है, मैं क्लोजर मैक्रोज़ सीख रहा हूं, और आश्चर्य है कि हम मेटाप्रोग्रामिंग के लिए केवल फ़ंक्शंस का उपयोग क्यों नहीं कर सकते हैं।क्लोजर, मैक्रोज़ ऐसा कुछ कर सकता है जो किसी फ़ंक्शन

जहाँ तक मुझे पता के रूप में स्थूल और समारोह के बीच अंतर यह है कि मैक्रो के तर्कों का मूल्यांकन नहीं किया जाता है, लेकिन डाटा संरचनाओं और प्रतीकों के रूप में पारित कर दिया है के रूप में वे कर रहे हैं, जबकि वापसी मान है का मूल्यांकन (जगह है जहाँ मैक्रो कहा जाता है में)। मैक्रो पाठक और मूल्यांकनकर्ता के बीच प्रॉक्सी के रूप में काम करता है, मूल्यांकन के पहले फॉर्म को मनमाने तरीके से बदलता है। आंतरिक रूप से वे सभी भाषा विशेषताओं, कार्यों, विशेष रूपों, शाब्दिक, रिकर्सन, अन्य मैक्रोज़ इत्यादि सहित उपयोग कर सकते हैं

कार्य विपरीत हैं। कॉल से पहले तर्कों का मूल्यांकन किया जाता है, वापसी मूल्य वापसी के बाद नहीं होता है। लेकिन मैक्रोज़ और फ़ंक्शंस की मिररिंग प्रकृति मुझे आश्चर्यचकित करती है, क्या हम मैक्रोज़ का उपयोग अपने तर्क (फॉर्म) को उद्धृत करके, फॉर्म को बदलने, फ़ंक्शन के अंदर मूल्यांकन करने, अंततः इसके मूल्य को वापस कर सकते हैं। क्या यह तर्कसंगत रूप से एक ही परिणाम नहीं देगा? बेशक यह असुविधाजनक होगा, लेकिन सैद्धांतिक रूप से, प्रत्येक संभावित मैक्रो के लिए समकक्ष फ़ंक्शन है?

यहाँ सरल इन्फ़िक्स मैक्रो

(defmacro infix 
    "translate infix notation to clojure form" 
    [form] 
    (list (second form) (first form) (last form))) 

(infix (6 + 6)) ;-> 12 

यहाँ एक समारोह उपयोग कर रहा है एक ही तर्क

(defn infix-fn 
    "infix using a function" 
    [form] 
    ((eval (second form)) (eval (first form)) (eval (last form)))) 

(infix-fn '(6 + 6)) ;-> 12 

अब है, इस धारणा सभी स्थितियों के लिए generalizable है, या फिर कुछ कोने मामलों में जहां मैक्रो सका हैं ' बाहर नहीं किया जा सकता है? अंत में, मैक्रोज़ फ़ंक्शन कॉल पर केवल एक वाक्य रचनात्मक चीनी हैं?

+3

ध्यान दें कि मैक्रोज़ को समय-समय पर मैक्रोएक्सप्शन-टाइम (आमतौर पर संकलन से पहले) के दौरान विस्तारित किया जाता है। संकलित कोड ऐसा होगा जैसे आपने हाथ से विस्तार लिखा था, इसलिए इसके लिए कोई प्रदर्शन दंड नहीं है। यह भी याद रखें कि 'eval' एक शून्य व्याख्यात्मक वातावरण में रूप का मूल्यांकन करता है। '(चलो [x 10] (infix-fn '(x + 6)))' => 'कंपाइलर अपवाद ... प्रतीक को हल करने में असमर्थ: x' – jkiiski

+0

ये अच्छे अंक हैं जिन्हें मैंने –

उत्तर

11

अगर मैं इसका उत्तर देने से पहले प्रश्न पढ़ता हूं तो इससे मदद मिलेगी।

आपका इन्फ़िक्स समारोह शाब्दिक साथ छोड़कर काम नहीं करता है:

(let [m 3, n 22] (infix-fn '(m + n))) 
CompilerException java.lang.RuntimeException: 
Unable to resolve symbol: m in this context ... 

यह @jkinski क्या विख्यात का परिणाम है: समय eval कार्य करता है, m चला गया है द्वारा।


मैक्रो क्या कार्यों नहीं कर सकते हैं कर सकते हैं?

हां। लेकिन अगर आप इसे एक समारोह के साथ कर सकते हैं, तो आपको आम तौर पर चाहिए।

मैक्रो

  • टाल मूल्यांकन के लिए अच्छा कर रहे हैं;
  • रूपों को कैप्चर करना;
  • पुन: व्यवस्थित वाक्यविन्यास;

इनमें से कोई भी कार्य नहीं कर सकता है।

आस्थगित मूल्यांकन

(defmacro unless [test then] 
    (list 'if (list 'not test) then))) 

... if-not के एक आंशिक क्लोन (प्रोग्रामिंग Clojure से Halloway & bedra द्वारा) पर विचार करें। यह

(defn safe-div [num denom] 
    (unless (zero? denom) (/ num denom))) 

परिभाषित करने के लिए उपयोग करते हैं ... जो शून्य से भाग रोकता है, nil लौटने:

(safe-div 10 0) 
=> nil 

हम एक समारोह के रूप में यह परिभाषित करने का प्रयास किया:

(defn unless [test then] 
    (if (not test) then)) 

.. ।

(safe-div 10 0) 
ArithmeticException Divide by zero ... 

unless के शरीर से पहले तर्क unless पर संभावित परिणाम का मूल्यांकन किया जाता है।

कैप्चरिंग फार्म और पुन: आयोजन सिंटेक्स

मान लीजिए Clojure कोई case रूप था।

(defmacro my-case [expr & stuff] 
    (let [thunk (fn [form] `(fn [] ~form)) 
     pairs (partition 2 stuff) 
     default (if (-> stuff count odd?) 
        (-> stuff last thunk) 
        '(constantly nil)) 
     [ks vs] (apply map list pairs) 
     the-map (zipmap ks (map thunk vs))] 
    (list (list the-map expr default)))) 

यह

  • की पसंद कुंजियों (ks) और इसी भाव (vs) के अलावा,
  • , parameterless fn रूपों के रूप में बाद लपेटता
  • : यहाँ एक किसी न किसी और के लिए तैयार विकल्प है
  • पूर्व से बाद के मानचित्र का नक्शा बनाता है,
  • एक ऐसा फॉर्म देता है जो फ़ंक्शन को देखकर वापस लौटाता है मानचित्र।

विवरण महत्वहीन नहीं हैं। मुद्दा यह है कि यह किया जा सकता है।

जब गिडो वैन रॉसम ने पायथन को केस स्टेटमेंट जोड़ने का प्रस्ताव दिया, तो समिति ने उसे नीचे कर दिया। तो पायथन के पास कोई केस स्टेटमेंट नहीं है। अगर रिच case कथन नहीं चाहता था, लेकिन मैंने किया, तो मेरे पास एक हो सकता है।


बस मस्ती के लिए, के if प्रपत्र की एक प्रचलित क्लोन ईजाद करने के लिए मैक्रो का उपयोग करते हैं। इसमें कोई संदेह नहीं है कि कार्यात्मक प्रोग्रामिंग सर्किलों में एक क्लिच है, लेकिन मुझे आश्चर्य से ले गया। मैंने if को आलसी मूल्यांकन के एक irreducible primitive के रूप में सोचा था।

एक आसान तरीका है my-case मैक्रो पर पिग्गी-बैक के लिए है:

(defmacro if-like 
    ([test then] `(if-like ~test ~then nil)) 
    ([test then else] 
    `(my-case ~test 
    false ~else 
    nil ~else 
    ~then))) 

यह प्रपंची और धीमी गति से है, और यह ढेर का उपयोग करता है और recur है, जो बंद होने में दफन हो जाता है खो देता है। तथापि ...

(defn fact [n] 
    (if-like (pos? n) 
    (* (fact (dec n)) n) 
    1)) 

(map fact (range 10)) 
=> (1 1 2 6 24 120 720 5040 40320 362880) 

... यह काम करता है, कम या ज्यादा।


कृपया, प्रिय पाठक, मेरे कोड में किसी भी त्रुटि को इंगित करें।

+0

में आलसी मूल्यांकन नहीं किया था उदाहरण तब तक कार्य करने तक लम्बा अभिव्यक्ति के रूप में गुजरकर भी किया जा सकता है। क्या ऐसे कुछ मामले हैं जहां लैम्ब्डा भी ऐसा नहीं करेंगे? –

+0

@TuomasToivonen मुझे लगता है कि लैम्ब्डा हमेशा ऐसा कर सकता है। जैसा कि आप जानते हैं, एक फ़ंक्शन क्या नहीं रोक सकता है, इसके तर्कों का मूल्यांकन है। आप निश्चित रूप से हमेशा लैम्बदास में कब्जे वाले गैर-मूल्यांकन फॉर्म के रूप में तर्क प्रदान कर सकते हैं। हम एक मैक्रो के रूप में एक 'अगर' दिखने के लिए भी लैम्ब्स का उपयोग कर सकते हैं: देखो, एम, कोई विशेष रूप नहीं। वास्तव में, मैं अभी यह करूँगा :)। – Thumbnail

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