[英]How to call macro, and pass arguments to it
似乎我對宏的理解是不完整的。 如何將參數傳遞給宏,並從函數中調用它們。 代碼下面看似簡單的代碼不起作用。
(defmacro bar [arg]
(println (symbol? arg)))
(defn foo [arg]
(bar arg))
(foo 'baz) => nil
定義foo時正在評估宏。 如果在repl中定義foo函數,則會注意到Clojure打印為true。
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
你需要引用宏的主體,否則它將被評估,因為它的返回值是nil,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))
這是編譯后,然后,您運行代碼並打印'nil'。 你會注意到(bar a)
會產生' a is not bound
'的錯誤,因為擴展是(println (symbol a))
,其中a
被評估,可能沒有值。 (bar 'a)
返回T
使用這個正確的bar
宏,你的函數foo
在編譯時會擴展為:
(defun foo (x)
(println (symbol? x))
它正確地計算(foo 'a)
和(foo 10)
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.