我想要的清單傳遞給宏,例如:如何將一個列表傳遞給通用lisp中的宏?
(defmacro print-lst (lst)
`(progn
,@(mapcar #'(lambda (x) `(print ,x)) lst)))
(let ((lst '(1 2 3)))
(print-lst lst))
它抓住了錯誤:「值是LST LST型不是」。
所以,我的問題是,這段代碼有什麼問題以及如何將列表傳遞給宏?
我想要的清單傳遞給宏,例如:如何將一個列表傳遞給通用lisp中的宏?
(defmacro print-lst (lst)
`(progn
,@(mapcar #'(lambda (x) `(print ,x)) lst)))
(let ((lst '(1 2 3)))
(print-lst lst))
它抓住了錯誤:「值是LST LST型不是」。
所以,我的問題是,這段代碼有什麼問題以及如何將列表傳遞給宏?
我不知道你爲什麼要把它定義爲一個宏而不是一個常規函數,但問題是宏不會評估它們的參數。如果你給它一個詞彙變量的名字,它看到的只是名字('LST
),而不是綁定的值。它正在抱怨(正確)符號'LST
不是一個列表,因此不是MAPCAR
的有效第二個參數。
你可以把它作爲(print-lst (1 2 3))
,但你可以在沒有宏觀做,只是做(mapC#'print lst)
你試圖用你的宏做的是擴大文字列表。
宏參數未被評估。所以,print-lst
實際上是收到符號lst
,而不是綁定到變量的列表。
你要麼aknowledge說,給print-lst
文字列表,或者您可以生成評估宏參數代碼:
(defmacro print-lst (lst)
(let ((item (gensym)))
;; Macros usually make sure that expanded arguments are
;; evaluated only once and in left-to-right order.
;;
;; In this case, we only have one argument and we only evaluate it once.
`(dolist (,item ,lst)
(print ,item))))
雖然,這顯然不是一個宏觀的一個很好的例子,它會更好是一個函數:
(defun print-lst (lst)
(dolist (item lst)
(print item)))
如果你想調用內聯到print-lst
,您可以諮詢您的實現文檔,看它是否注重(declaim (inline print-lst))
。
另一種選擇是使用編譯器宏來補充函數,以在編譯時對參數的求值是已知值的內聯調用,但再次查看您的實現是否注意編譯器宏:
(define-compiler-macro print-lst (&whole form lst &environment env)
(declare (ignorable env))
;; Some implementations have an eval function that takes an environment.
;; Since that's not standard Common Lisp, we don't use it in constantp.
(if (constantp lst)
`(progn
,@(mapcar #'(lambda (item)
`(print ,item))
(eval lst)))
;; Return the original form to state you didn't transform code.
form))
您的代碼不必要地使用了宏。其實,你可以像上面提到的那樣評估(mapcar#'print'(1 2 3))。您也可以使用(print-lst(1 2 3))而不使用列表引號,但不推薦使用它,因爲這不符合一般慣例以參數調用函數。總而言之,當調用一個宏時,如果你期望它被評估,你不應該引用一個沒有評估逗號'''的符號,因爲將從字面上代入宏模板。
例如
(setq a 1)
;;A won't be evaluated without the comma
(defmacro foo (x) `(progn ,(print x))
(foo 'a) ;;=> 'A (A is returned since (print 'a) is evaluated)
(foo a) ;;=> A (1 is returned since (print a) is evaluated)
;;A is evaluated
(defmacro bar (x) `(print ,x))
(bar 'a) ;;=> A
(bar a) ;;=> 1
您的代碼:
(defmacro print-lst (lst)
`(progn
,@(mapcar #'(lambda (x) `(print ,x)) lst)))
的「mapcar」的形式將被評估作爲一個整體,但「樂善堂」將只被替換爲你傳遞什麼。
我可以定義的,而不是一個宏功能來解決這個問題:
(defun print-lst (lst)
(mapcar #'eval
(mapcar #'(lambda (x) `(print ,x)) lst)))
然後:
(let ((lst '(1 2 3)))
(print-lst lst))
;;=>
1
2
3
(1 2 3)
如果你有興趣的問題,你標題,你可以看到我的另一回答關於此: