当我不想要它时,Lisp宏评估表达式

时间:2011-11-30 07:40:25

标签: macros lisp

我正在尝试在lisp中编写一个宏,它返回传递给它的第n个表达式,并且只计算该表达式。例如:

(let ((n 2))
  (nth-expr n (/ 1 0) (+ 1 2) (/ 1 0)))

应该返回3.我得到除以0的错误。我的宏定义如下:

(defmacro nth-expr (n &rest expressions)
  (let ((i (gensym))
        (expr (gensym)))
    `(do ((,i 1 (1+ ,i))
          (,expr ,expressions (cdr ,expr)))
         ((= ,i ,n) (car ,expr)))))

知道我做错了什么吗?感谢。

编辑:

感谢@Vsevolod Dyomkin帮助我完成上述部分。现在还有一个问题。我试图做的时候

(let ((n 3) (x "win") (y "lose"))
  (nth-expr n (princ x) (princ x) (princ y) (princ x)))

我收到错误Error: Attempt to take the value of the unbound variable 'Y'

我的更新代码如下所示:

(defmacro nth-expr (n &rest expressions)
  (let ((i (gensym))
        (expr (gensym))
        (num (gensym)))
    `(let ((,num (eval ,n)))
       (do ((,i 1 (1+ ,i))
            (,expr ',expressions (cdr ,expr)))
           ((= ,i ,num) (eval (car ,expr)))))))

4 个答案:

答案 0 :(得分:5)

主要是FIRST提出扩展。

工作代码应该是什么样的?宏用法将扩展到的代码?

然后你编写宏来创建这样的代码。

确保您没有评估宏中提供的任何代码。

您的问题的一个简单有用的扩展目标是CASE表单。

(case n
  (0 (do-this))
  (1 (do-that))
  (2 (do-something-else)))

现在编写一个将(nth-expr n (/ 1 0) (+ 1 2) (/ 1 0))扩展为CASE表格的宏应该很容易......

答案 1 :(得分:4)

这里不需要eval,也不需要在列表中存储表达式。

正确的实施如下:

(defmacro nth-expr (n &rest expressions)
    `(case ,n
        ,@(loop for e in expressions
                for n from 1
                collect
                `((,n) ,e))))

您的示例展开为:

(CASE N ((1) (/ 1 0)) ((2) (+ 1 2)) ((3) (/ 1 0)))

答案 2 :(得分:1)

你需要qoute ,expressions,就像这样:

(defmacro nth-expr (n &rest expressions)
  (let ((i (gensym))
        (expr (gensym)))
    `(do ((,i 1 (1+ ,i))
          (,expr ',expressions (cdr ,expr)))
         ((= ,i ,n) (car ,expr)))))

否则,您将得到的是 - expressions列表按原样插入:

CL-USER> (let ((n 2))
           (macroexpand-1 '(nth-expr n (/ 1 0) (+ 1 2) (/ 1 0))))
(DO ((#:G864 1 (1+ #:G864))
     (#:G865 ((/ 1 0) (+ 1 2) (/ 1 0)) (CDR #:G865)))
    ((= #:G864 N) (CAR #:G865)))

答案 3 :(得分:0)

第二个示例中的错误是EVAL无法看到您的词汇绑定NXY变量。

来自EVAL的CLHS:

  

在当前动态环境 null词法环境中评估表单

如果您将XY声明为特殊:

,则会有效
(let ((n 3) (x "win") (y "lose"))
  (declare (special x y))
  (nth-expr n (princ x) (princ x) (princ y) (princ x)))

但这仍然不如SK-logic建议的CASE解决方案好。