這將有助於通過macroexpand
的鏡頭來查看您的示例,它是調試宏的基本工具。
例1:
(defmacro triple-do [form]
(list 'do form form form))
user=> (triple-do (println "test"))
記住宏應該返回,將在運行時執行的列表。讓我們來看看這個宏的回報:
(macroexpand '(triple-do (println "test")))
;; (do (println "test") (println "test") (println "test"))
所以也沒有執行代碼,而是返回表示一旦展開宏將要執行的代碼清單。這類似於在REPL嘗試下面的代碼片段:記住
(+ 1 2 3)
;; 6
(list '+ 1 2 3)
;; (+ 1 2 3)
有了這個,讓我們來看例2:
(defmacro triple-do [form]
(do form form form))
user=> (triple-do (println "test"))
注意如何宏現在不返回一個列表。它只是執行do
形式返回的最後一條語句是傳遞的形式,這可以通過擴展宏很容易地看到:
(macroexpand '(triple-do (println "test")))
;; (println "test")
這就是爲什麼你最終有一個單一的打印語句。
這應該給你一個關於例3的線索:
(defmacro test-macro [form] (do form (println "hard code test")))
user=> (test-macro (println "hello"))
這是一個有點棘手,但我們仍然展開:
(macroexpand '(test-macro (println "hello")))
;; hard code test <= this gets print before the macro fully expands
;; nil <= the expansion yields nil
再次,因爲你沒有返回一個列表,而是隻需執行一個do
表單,它只是在宏內運行println
調用,並且由於println
返回nil,這就是擴展的結果。
爲了說明我的觀點,這是你必須如何修改您的宏,以達到所需的行爲:
(defmacro test-macro [form] (list 'do form (println "hard code test")))
(test-macro (println "hello"))
;; hard code test
;; hello
我希望這會清除你的東西。
只要記住這個:宏應該返回表示您希望在運行時執行的代碼的列表。
謝謝leonardoborges。我很清楚 – user3131318
我很高興它有幫助。請考慮接受這個答案,如果它清除了足夠的東西給你。謝謝。 – leonardoborges