2012-09-24 70 views
2

我想更好地瞭解listing 13.3 in The Joy of Clojure。它是一個生成其他宏的宏(很像在Clojure 1.4中如何實現原始數組函數)。如何編寫打印自己的後綴的嵌套宏?

我想寫一個宏,它在運行時只是打印生成的宏的後綴。即

user=> (nested-macro joe) 
user=> (nested-macro-named-joe) 
hello from joe 
nil 

我無法使這項工作。

這裏是我試過:

嘗試1

(defmacro nested-macro [name] 
    `(defmacro ~(symbol (str "nested-macro-named-" name)) 
    [] 
    `(println "hello from " ~name))) 

輸出:

hello from #<core$name [email protected]>

嘗試2

(defmacro nested-macro [name] 
    (let [local-name name] 
    `(defmacro ~(symbol (str "my-custom-macro-named-" ~local-name)) 
     [] 
     `(println "hello from " ~local-name)))) 

錯誤

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

嘗試3:

(defmacro nested-macro [name] 
    (let [local-name name] 
    `(defmacro ~(symbol (str "nested-macro-named-" name)) 
     [] 
     `(println "hello from " ~(symbol local-name))))) 

編譯器錯誤:

CompilerException java.lang.RuntimeException: No such var: joy.dsl/local-name

只爲它赫克,我也嘗試添加#的局部變量,以類似結果同上,但與「汽車」的名稱,如local-name__1127__auto__我沒有看到然而,作爲解決方案的一部分。

我該如何做這項工作?

回答

3

要知道宏指令出了什麼問題,我總是使用macroexpand-1

從你的第一個例子:

(macroexpand-1 '(nested-macro joe)) 

結果:

(clojure.core/defmacro nested-macro-named-joe [] 
    (clojure.core/seq 
    (clojure.core/concat 
     (clojure.core/list (quote clojure.core/println)) 
     (clojure.core/list "hello from ") 
     (clojure.core/list clojure.core/name)))) 

如果你看看過去的PARAM,它表明你正在使用clojure.core /名稱,這可能是不你想要什麼,因爲你實際上需要名爲「name」的參數。

要解決它,只需添加另一所享有的name PARAM,但正如其名PARAM實際上是一個符號,你真正想要的是得到它的名字,如:

(defmacro nested-macro [the-name] 
    `(defmacro ~(symbol (str "nested-macro-named-" the-name)) 
    [] 
    `(println "hello from " ~~(name the-name)))) 
+2

''〜 〜name'是在類似情況下引用的更一般的解決方案 - 並不總是如此,您很樂意獲取值的字符串表示形式。 – amalloy

+1

將'~~名稱替換爲~~名稱導致CompilerException java.lang.RuntimeException:無法在此上下文中解析符號:joe編譯:(NO_SOURCE_PATH:1)'。 – DanLebrero

+3

呃,嵌套的引用很難。我想這是'〜'〜name'來停止內部宏試圖解析名稱。 – amalloy