我想知道这两个nth的定义是否相等:
予。被定义为宏:
(defmacro -nth (n lst)
(defun f (n1 lst1)
(cond ((eql n1 0) lst1)
(t `(cdr ,(f (- n1 1) lst1)))))
`(car ,(f n lst)))
II。被定义为一堆函数:
(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)))
我有正确的想法吗?宏定义是评估表达式,在其体内构建吗?
答案 0 :(得分:4)
好的,让我们从头开始。
宏用于创建通常依赖于宏输入的新表单。在编译或评估代码之前,必须展开。扩展宏是在评估使用它的表单之前发生的过程。这种扩张的结果通常是一种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
此宏创建有用的词法绑定,捕获变量it
。在检查条件后,您不必重新计算结果,它可以在表格中访问,然后是'和其他'。它只是一个函数是不可能的,它已经在语言中引入了新的控件构造。但宏不仅仅是创造词汇环境。
宏是一个强大的工具。要完全描述你可以用它做什么是不可能的,因为你可以做任何事情。但nth
不是你需要宏的东西。要构建nth
的克隆,您可以尝试编写递归函数。
重要的是要注意LISP宏是编程世界中最强大的东西,而LISP是唯一拥有这种能力的语言; - )
为了激励你,我会推荐这篇文章:http://www.paulgraham.com/avg.html
要掌握宏,请从以下内容开始:
http://www.gigamonkeys.com/book/macros-defining-your-own.html
然后可能是Paul Graham" On Lisp"然后"让Over Lambda"。
答案 1 :(得分:1)
无需宏和eval
进行抽象以获取列表的第n个元素。除非索引是文字编号,否则您的宏-nth
甚至不起作用。试试这个:
(defparameter test-list '(9 8 7 6 5 4 3 2 1 0))
(defparameter index 3)
(nth index test-list) ; ==> 6 (this is the LISP provided nth)
(-nth index test-list) ; ==> ERROR: index is not a number
第n个典型的递归解决方案:
(defun nth2 (index list)
(if (<= index 0)
(car list)
(nth2 (1- index) (cdr list))))
(nth2 index test-list) ; ==> 6
典型的循环版本
(defun nth3 (index list)
(loop :for e :in list
:for i :from index :downto 0
:when (= i 0) :return e))
(nth3 index test-list) ; ==> 6
通常情况下,macro
是您在看到自己重复太多而无法使用函数进一步抽象代码时使用的东西。您可以创建一个宏来节省编写样板代码的时间。当然,有一个不是标准代码的权衡,所以你经常在编写样板后写宏。
eval
。通常,您可以使用funcall
和apply
。 eval
仅适用于全局范围,因此您会松开闭包变量。