簡體   English   中英

如何調用宏,並將參數傳遞給它

[英]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)))

宏應該生成代碼。 它將源表達式作為參數並創建新的源。

  1. 你的宏采取什么來源?
  2. 你的宏生成了什么來源?

讓我們來看看:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM