【问题标题】:Is evaluating of constructed evaluation equal to macro?构造评估的评估是否等于宏观?
【发布时间】:2014-06-04 15:28:35
【问题描述】:

我想知道这两个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)))

我的想法正确吗?宏定义是表达式的求值,是在它的主体中构造的吗?

【问题讨论】:

    标签: macros lisp common-lisp evaluation


    【解决方案1】:

    好的,让我们从头开始。

    宏用于创建通常依赖于宏输入的新表单。在编译或评估代码之前,必须扩展宏。宏的扩展是在评估使用它的形式之前发生的过程。这种扩展的结果通常是一个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。检查条件后,您不必重新计算结果,它可以以'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”。

    【讨论】:

      【解决方案2】:

      宏和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 不应该被使用,除非你真的必须这样做。通常您可以使用funcallapplyeval 仅在全局范围内有效,因此您可以释放闭包变量。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-08-15
        • 2012-02-03
        • 1970-01-01
        • 1970-01-01
        • 2012-11-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多