我想知道 nth 的这两个定义是否相等:
我。定义为宏:
(defmacro -nth (n lst)
(defun f (n1 lst1)
(cond ((eql n1 0) lst1)
(t `(cdr ,(f (- n1 1) lst1)))))
`(car ,(f n lst)))
二。被定义为一堆函数:
(defun f (n lst)
(cond ((eql n 0) lst)
(t `(cdr ,(f (- n 1) lst)))))
(defun f1 (n lst)
`(car ,(f n `',lst)))
(defun --nth (n lst)
(eval (f1 n lst)))
我的想法正确吗?宏定义是表达式的求值,在其主体中构造?
最佳答案
好的,让我们从头开始。
宏用于创建通常依赖于宏输入的新表单。在编译或评估代码之前,必须展开宏。宏的扩展是在评估使用它的形式之前发生的过程。这种扩展的结果通常是 lisp 形式。
所以在一个宏里面有几个层次的代码。
- 未引用的代码将在宏扩展期间进行评估(不是在运行时!),在您的示例中,您在扩展宏时定义函数
f
(为了什么?) ; - 接下来是引用(使用通常的引号或反引号甚至嵌套反引号)代码,它将成为宏扩展结果的一部分(以其文字形式);您可以控制在宏扩展期间将评估代码的哪一部分以及将保持完整(引用,部分或全部)的代码。这允许人们在执行之前构建任何东西。
宏的另一个特点是它在扩展前不评估其参数,而函数会。为了让您了解什么是宏,请看这个(首先想到的是):
(defmacro aif (test then &optional else)
`(let ((it ,test))
(if it ,then ,else)))
你可以这样使用它:
CL-USER> (defparameter *x* '((a . 1) (b . 2) (c . 3) (d . 4)))
*X*
CL-USER> (aif (find 'c *x* :key #'car) (1+ (cdr it)) 0)
4
这个宏创建有用的词法绑定(bind),捕获变量 it
。检查条件后,您不必重新计算结果,它可以以“then”和“else”的形式访问。仅仅一个函数是不可能做到的,它在语言中引入了新的控件构造。但宏观不仅仅是创造词汇环境。
宏是一个强大的工具。不可能完全描述您可以用它做什么,因为您可以做任何事情。但是 nth
不是你需要宏的东西。要构造 nth
的克隆,您可以尝试编写一个递归函数。
重要的是要注意 LISP 宏是编程世界中最强大的东西,而 LISP 是唯一具有这种能力的语言;-)
为了启发您,我推荐这篇文章:http://www.paulgraham.com/avg.html
要掌握宏,从这样的事情开始:
http://www.gigamonkeys.com/book/macros-defining-your-own.html
然后可能是 Paul Graham 的“On Lisp”,然后是“Let Over Lambda”。
关于macros - 构建评估的评估是否等于宏观?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24041571/