看來我對宏的理解並不完整。 如何將參數傳遞給宏,並從函數中調用它們。 代碼下面看似簡單的代碼不起作用。如何調用宏並將參數傳遞給它
(defmacro bar [arg]
(println (symbol? arg)))
(defn foo [arg]
(bar arg))
(foo 'baz) => nil
看來我對宏的理解並不完整。 如何將參數傳遞給宏,並從函數中調用它們。 代碼下面看似簡單的代碼不起作用。如何調用宏並將參數傳遞給它
(defmacro bar [arg]
(println (symbol? arg)))
(defn foo [arg]
(bar arg))
(foo 'baz) => nil
定義foo時正在對宏進行評估。如果你在repl中定義foo函數,你會注意到Clojure輸出的是真實的。
user=> (defmacro bar [arg]
(println (symbol? arg)))
#'user/bar
user=> (defn foo [arg]
(bar arg))
true ; <= This is the print from your macro
; (it prints true, because arg is a symbol)
#'user/foo
您需要引用宏的主體,否則將被評估,因爲它的返回值爲零,foo將簡單地返回nil。
(defmacro bar [arg]
`(println (symbol? ~arg)))
宏應該生成代碼。它將源表達式作爲參數並創建新的源。
讓我們來看看:
user=> (defmacro bar [arg]
(println (symbol? arg)))
#'user/bar
user=> (bar 1)
false
nil
user=> (bar 'a)
false
nil
user=> (bar a)
true
nil
這是擴展:
user=> (macroexpand-1 '(bar a))
true
它不會產生任何有用的代碼。
對於需要「工作」的宏,它需要返回代碼,通常作爲列表表達式。因此,對於你的意圖,你需要提供:
(defmacro bar (arg)
`(println (symbol? ,arg)))
(這將使用quasiquote作爲構建列表更方便的符號),在您使用bar
使用擴展,通過運行defmacro碼點,產生該清單。該列表然後被編譯。因此,例如:
(progn (bar 10))
擴展爲
(progn (println (symbol? 10))
這是編譯,然後,以後,你跑被打印的代碼和「零」。你會注意到(bar a)
將產生'a is not bound
'的錯誤,因爲擴展是(println (symbol a))
,因此a
被評估,可能沒有值。 (bar 'a)
返回T
。
有了這個正確bar
宏,你的函數foo
,在編譯時,將擴大到:
其計算(foo 'a)
和(foo 10)
正常。
如果我理解正確,那麼foo的定義將被擴展爲(println(symbol?arg))應該爲(foo'baz)打印爲真。我在這裏錯過了什麼? – navgeet 2013-03-16 11:40:59
@navgeet,不,你寫的宏不會擴展到'(println(symbol?arg))'。宏只是一個函數,它必須返回擴展形式。如果你想得到你所描述的內容,你應該把宏的主體改成'(println(symbol?〜arg))。 – 2013-03-16 13:20:20