【发布时间】:2019-09-08 05:59:13
【问题描述】:
所以我想编写一个 all 宏,它接受一个元素列表,如果它们都是非假的,则返回。我想把它作为一个宏来做,比如
(defmacro all (ls)
`(and ,@ls))
当我使用
进行测试时有效(all (1 2 3))
但不是
(all '(1 2 3))
或任何其他列表。我不太确定为什么。我做错了什么?
【问题讨论】:
标签: macros common-lisp
所以我想编写一个 all 宏,它接受一个元素列表,如果它们都是非假的,则返回。我想把它作为一个宏来做,比如
(defmacro all (ls)
`(and ,@ls))
当我使用
进行测试时有效(all (1 2 3))
但不是
(all '(1 2 3))
或任何其他列表。我不太确定为什么。我做错了什么?
【问题讨论】:
标签: macros common-lisp
1. ',引号是什么意思
's-expression只是(QUOTE s-expression)的语法缩写,所以'(1 2 3)是二元素列表(QUOTE (1 2 3))的缩写
2。如何评估宏
宏是将一种形式(s 表达式)转换为另一种形式的函数,通常用于向语言添加新的句法结构。
因此,宏的参数不会被计算。它们按字面意思理解并绑定到宏参数。
因此,宏 all 在使用时将列表参数绑定到 ls 参数而不进行任何评估,并将列表转换为插入原子 and 作为第一个元素的新列表:
(all (1 2 3)) => (AND 1 2 3)
然后对生成的表单进行解释或编译以供后续评估。
如果你写(all '(1 2 3),这相当于(all (QUOTE (1 2 3)),转换如下:
(all '(1 2 3)) => (all (QUOTE (1 2 3)) => (AND QUOTE (1 2 3))
这可能与您所期望的不同,并且会产生几个错误(变量QUOTE 未绑定,(1 2 3) 的汽车不是函数名称或 lambda 表达式)。
3.调试宏
如果您想查看宏是如何展开的,可以使用macroexpand-1 原语函数(参见manual):
CL-USER> (macroexpand-1 '(all (1 2 3)))
(AND 1 2 3)
CL-USER> (macroexpand-1 '(all '(1 2 3)))
(AND QUOTE (1 2 3))
【讨论】:
(let ((x '(1 2 3))) (all x)),则会收到错误:“值 X 不是预期的类型 LIST。”。这是因为与ls 关联的s 表达式是符号X,而不是它的值。
所以这行得通。
(defmacro all (ls)
`(reduce (lambda (a b) (and a b)) ,ls))
虽然它不是那么简洁或让我满意。
【讨论】: