2011-12-24 15 views
6

का उपयोग कर मैक्रो को कार्यान्वित करते समय कोड टेम्पलेटिंग कैसे करें, मैं एक इंफिक्स सूची को एक उपसर्ग सूची में परिवर्तित करने के लिए मैक्रो को कार्यान्वित करने का प्रयास कर रहा हूं। मुझे निम्न प्रकार की समस्या आती है:क्लोजर में, रिकर्सन

;;this works 
(defmacro recursive-infix [form] 
    (list (second form) (first form) 
     (if (not (seq? (nth form 2))) 
      (nth form 2) 
      (recursive-infix (nth form 2))))) 

;;this doesn't work 
(defmacro my-recursive-infix [form] 
    `(~(second form) ~(first form) 
     (if (not (seq? ~(nth form 2))) 
      ~(nth form 2) 
      (my-recursive-infix ~(nth form 2))))) 

(macroexpand '(recursive-infix (10 + 10))) 
;;get (+ 10 10) 

(macroexpand '(my-recursive-infix (10 + 10))) 
;;get (+ 10 (if (clojure.core/not (clojure.core/seq? 10)) 10 (user/my-recursive-infix 10))) 

(recursive-infix (10 + 10)) 
;;get 20 

(my-recursive-infix (10 + 10)) 
;;Don't know how to create ISeq from: java.lang.Integer [Thrown class java.lang.IllegalArgumentException] 

समस्या कहां है? कोड टेम्पलेटिंग के साथ मैक्रो को सही तरीके से परिभाषित कैसे करें?

पीएस मैंने कोड को इस में बदल दिया और यह काम करता है, क्यों? क्या अंतर ?:

(defmacro my-recursive-infix [form] 
    (if (not (seq? (nth form 2))) 
    `(~(second form) ~(first form) ~(nth form 2)) 
    `(~(second form) ~(first form) (my-recursive-infix (nth form 2))))) 
+0

डालने से कोई लेना देना है "अगर ब्लॉक" बैकक्वॉट की बाध्यकारी रेंज में? – lkahtz

उत्तर

13

मूल संस्करण में, (if (not ...)) जांच संकलन समय जो हो रहा था; इसके बजाय आपने इसे विस्तारित कोड में शामिल किया है। तो यहां एक न्यूनतम परिवर्तन है जो इसे आपके जैसा कार्य करने के लिए प्राप्त करेगा - यह प्रभावी रूप से मूल जैसा ही है, लेकिन उद्धृत किया गया है और क्या नहीं है "फ़्लिपिंग"।

(defmacro my-recursive-infix [form] 
    (let [third (nth form 2)] 
    `(~(second form) ~(first form) 
     ~(if (not (seq? third)) 
     third 
     `(my-recursive-infix ~third))))) 

हालांकि, यह समय से आगे प्रपत्र के टुकड़े बाहर निकलने के लिए, बल्कि यथा-स्थान से destructuring उपयोग करने के लिए एक सा बेहतर होता है:

(defmacro my-recursive-infix [form] 
    (let [[x op y] form] 
    `(~op ~x ~(if (not (seq? y)) 
       y 
       `(my-recursive-infix ~y))))) 

और बेहतर अभी भी, वास्तव में, स्थानांतरित करने के लिए है गैर पुनरावर्ती मामले के बाहर, ताकि (क) यह शाब्दिक संख्या के लिए काम करता है, और (ख) कोड अधिक क्या यह करने के लिए फैलता है जैसा दिखता है:

(defmacro my-recursive-infix [form] 
    (if-not (seq? form) 
    form 
    (let [[x op y] form] 
     `(~op ~x (my-recursive-infix ~y))))) 
+0

बहुत बहुत धन्यवाद @amalloy - यह वास्तव में मुझे मेरी समस्या पर हमला करने के लिए एक कम संकुचित तरीका देता है (https://stackoverflow.com/questions/41555991/mismatched-argument-count-to-recur-in-syntax-quoted-macro) , लेकिन मैं अंतिम कोड ब्लॉक में सटीक चरणों को समझने की कोशिश कर रहा हूं। क्या इस मामले में रिकर्सन सही ढंग से काम कर रहा है? मैं पास कर रहा हूं (1 + 2 + 3) 'फॉर्म' के रूप में, लेकिन यह केवल पहले दो ऑपरेटरों के योग को वापस कर रहा है। साथ ही, क्या मैं 'seq?' सोचने में सही हूं, आवर्ती 'y' मान को जांचना एक वैध रूप है, यह निर्धारित करने के लिए कि फिर से दोबारा शुरू करना है या नहीं? – Ooberdan

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