2012-10-09 29 views
7

Đối với thực tế, tôi đã xác địnhRắc rối với clojure quote-paren `(...) vĩ mô

(defmacro quote-paren 
    "body -> `(body)" 
    [& body] 
    `([email protected])) 

trong đó có việc chuyển đổi dự kiến ​​(quote-paren body) =>` `(cơ thể)`. Dường như để đáp ứng một vài xét nghiệm cơ bản:

user=> (macroexpand-1 `(quote-paren 3 4 5)) 
(3 4 5) 
user=> (macroexpand-1 `(quote-paren println "hi")) 
(clojure.core/println "hi") 
user=> (macroexpand-1 `(quote-paren (println "hi"))) 
((clojure.core/println "hi")) 

Tuy nhiên, tôi đã thử nghiệm nó với điều này do-while vĩ mô (sửa đổi từ here):

(defmacro do-while 
    [test & body] 
    (quote-paren loop [] 
    [email protected] 
    (when ~test 
     (recur)))) 

(def y 4) 
(do-while (> y 0) 
    (def y (dec y))) 

Nhưng kết quả là

IllegalStateException Attempting to call unbound fn: #'clojure.core/unquote-splicing clojure.lang.Var$Unbound.throwArity (Var.java:43) 

Tôi không hiểu điều này, bởi vì từ những gì tôi có thể thấy macro 'trích dẫn-paren' hoạt động tốt (với ~ @ body được cắm vào):

user=> (macroexpand-1 
     `(quote-paren loop [] 
      (def y (dec y)) 
      (when ~test 
       (recur)))) 

(clojure.core/loop [] (def user/y (clojure.core/dec user/y)) (clojure.core/when #<core$test [email protected]> (recur))) 

Nhưng cố gắng macroexpand do-while gây ra một "unbound fn". Có cái gì đó tinh tế tôi đang thiếu?

Trả lời

3

mất tích cú pháp-quote trước quote-paren

user> (defmacro do-while 
    [test & body] 
    `(quote-paren loop [] 
    [email protected] 
    (when ~test 
     (recur)))) 
#'user/do-while 

mà sau đó mở rộng đúng cách:

user> (macroexpand '(do-while (> y 0) 
         (def y (dec y)))) 
(loop* [] (def y (dec y)) (clojure.core/when (> y 0) (recur))) 

và dường như làm việc:

user> (def y 4) 
#'user/y 
user> (do-while (> y 0) 
    (def y (dec y))) 
nil 
user> 
+1

và cũng giống như một lời nhận xét bên: using (def y ...) để kiểm soát vòng lặp có thể có hậu quả không mong muốn không liên quan đến câu hỏi này ;-) –

+0

Hmm, bạn nói đúng, nhưng kiểu đánh bại đó là mục đích của bài tập của tôi. Có anyway để thực hiện một báo giá-paren thay thế '(quote-paren stuff)' với ''(stuff)'? Tóm lại, làm cho nó không cần thiết để viết 'trong định nghĩa macro. – spacingissue

+0

Tôi đã thử thay thế '(quote-paren stuff)' bằng '(quote (stuff))' nhưng có vẻ như ngừng nhận ra các biến; đó là '(defmacro do-while [test & body] (trích dẫn (vòng [] ~ @ body (khi ~ test (recur)))))' và chạy kết quả trong 'CompilerException java.lang. RuntimeException: Không thể giải quyết biểu tượng: thân trong ngữ cảnh này, biên dịch: (NO_SOURCE_PATH: 58) 'Nếu điều này được giải quyết tốt nhất trong một câu hỏi khác, mặc dù, tôi sẽ hiểu. – spacingissue

Các vấn đề liên quan