Macros 建构性评价是否等同于宏观评价?

Macros 建构性评价是否等同于宏观评价?,macros,lisp,common-lisp,evaluation,Macros,Lisp,Common Lisp,Evaluation,我想知道这两个n的定义是否相等: I.定义为宏: (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))))) (d

我想知道这两个n的定义是否相等:

I.定义为宏:

(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
    ,当宏被扩展时(为了什么?)
  • 接下来是引用的代码(使用通常的引号或反引号,甚至嵌套的反引号),它将成为宏扩展结果的一部分(以文本形式);您可以控制在宏扩展期间对代码的哪些部分求值,以及哪些部分保持不变(引用、部分或完全)。这允许在执行之前构造任何内容
宏的另一个特性是,它在展开之前不计算其参数,而函数计算参数。要让您了解什么是宏,请参见以下内容(这只是我想到的第一件事):

您可以这样使用它:

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
。检查条件后,您不必重新计算结果,它可以通过“then”和“else”形式访问。仅仅使用一个函数是不可能的,它在语言中引入了新的控件结构。但宏不仅仅是创建词汇环境

宏是一个强大的工具。不可能完全描述你能用它做什么,因为你什么都能做。但是
n
并不是需要宏来实现的。要构造第n个的克隆,可以尝试编写递归函数

需要注意的是,LISP宏是编程世界中最强大的东西,LISP是唯一具有这种能力的语言;-)

为了启发您,我推荐这篇文章:

要掌握宏,请从以下内容开始:

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


然后可能是保罗·格雷厄姆的《口齿不清》,然后是《放过拉姆达》。

好的,让我们从头开始

宏用于创建通常依赖于宏输入的新表单。在编译或计算代码之前,必须展开宏。宏的展开是在对使用宏的窗体求值之前进行的过程。这种扩展的结果通常是lisp格式

因此,在宏中有几个级别的代码

  • 未引用的代码将在宏扩展期间(不是在运行时!)进行计算,在您的示例中,您定义了函数
    f
    ,当宏被扩展时(为了什么?)
  • 接下来是引用的代码(使用通常的引号或反引号,甚至嵌套的反引号),它将成为宏扩展结果的一部分(以文本形式);您可以控制在宏扩展期间对代码的哪些部分求值,以及哪些部分保持不变(引用、部分或完全)。这允许在执行之前构造任何内容
宏的另一个特性是,它在展开之前不计算其参数,而函数计算参数。要让您了解什么是宏,请参见以下内容(这只是我想到的第一件事):

您可以这样使用它:

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
。检查条件后,您不必重新计算结果,它可以通过“then”和“else”形式访问。仅仅使用一个函数是不可能的,它在语言中引入了新的控件结构。但宏不仅仅是创建词汇环境

宏是一个强大的工具。不可能完全描述你能用它做什么,因为你什么都能做。但是
n
并不是需要宏来实现的。要构造第n个的克隆,可以尝试编写递归函数

需要注意的是,LISP宏是编程世界中最强大的东西,LISP是唯一具有这种能力的语言;-)

为了启发您,我推荐这篇文章:

要掌握宏,请从以下内容开始:

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


然后可能是Paul Graham的“On Lisp”,然后是“Let Over Lambda”。不需要宏或
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 
通常,当您看到自己的代码重复太多,无法用函数进一步抽象代码时,可以使用
宏。您可以制作一个宏来节省编写样板代码的时间。当然,不是标准代码有一个折衷,所以通常在编写样板文件几次之后再编写宏


eval
不应使用,除非您真的必须使用。通常,您可以使用
funcall
apply
进行操作
eval
仅在全局范围内工作,因此可以释放闭包变量。

不需要宏或
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 
通常,当您看到自己的代码重复太多,无法用函数进一步抽象代码时,可以使用
宏。您可以制作一个宏来节省编写样板代码的时间。当然,不是标准代码会有一个折衷,所以你通常