我想一个列表传递给宏,例如:
(defmacro print-lst (lst)
`(progn
,@(mapcar #'(lambda (x) `(print ,x)) lst)))
(let ((lst '(1 2 3)))
(print-lst lst))
它抓住了错误:“值是LST LST型不是”。
所以,我的问题是,什么是错这段代码,以及如何通过列表的宏?
我想一个列表传递给宏,例如:
(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))
您的代码使用不必要宏。 其实,你可以的eval(mapcar# '打印'(1 2 3))上述的人。 您还可以使用(打印LST(1 2 3))无单引号,但不推荐,因为这不符合一般的做法来调用带有参数的功能。
总而言之,调用宏时,你不应该举一个符号,而一个eval逗号“”如果你指望它来评价,因为它会从字面上代入宏模板。
如
(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)
如果你得到了题为感兴趣的问题,你可以看到我这个另一种答案:
我该如何申请“或”在elisp的列表