Macros Lisp宏的问题

Macros Lisp宏的问题,macros,lisp,common-lisp,mcl,Macros,Lisp,Common Lisp,Mcl,我正试图用Lisp编写一个宏,用它自己重新实现let。这是一项没有实际目的的琐碎工作;然而,在回答了一个相关的问题之后,我意识到我应该更多地了解宏。它们被吹捧为Lisp的一大优点,但我很少使用它们 不管怎样,以下是我第一次尝试的: (defmacro mylet (args &rest exp) `(let ,args (dolist (x ,exp) x))) 但当我尝试以下方法时: (mylet ((a 5) (b 2)) (print (+ a b))) 这引发了一个错误:

我正试图用Lisp编写一个宏,用它自己重新实现
let
。这是一项没有实际目的的琐碎工作;然而,在回答了一个相关的问题之后,我意识到我应该更多地了解宏。它们被吹捧为Lisp的一大优点,但我很少使用它们

不管怎样,以下是我第一次尝试的:

(defmacro mylet (args &rest exp) `(let ,args (dolist (x ,exp) x)))
但当我尝试以下方法时:

 (mylet ((a 5) (b 2)) (print (+ a b)))
这引发了一个错误:

  #1=(PRINT (+ A B)) is not a symbol or lambda expression in the form (#1#) .
args(a和b)设置正确,但print语句不起作用。我想这是因为我使用了两个级别的间接寻址——指的是我在宏中创建的变量。但我似乎不知道如何修复它!有什么想法吗?

您的宏将扩展到:

(LET ((A 5) (B 2))
  (DOLIST (X ((PRINT (+ A B)))) X))
这是无效的,因为
((PRINT(+ab)))
不是有效的表达式。还有一个问题是,在宏扩展中使用插入符号可能会导致变量捕获,但这并不直接相关(请参阅)

在这里使用DOLIST是不必要的,并且经过编译以获得正确的结果(您必须将所有子表单转换为匿名函数,以便将它们粘贴到列表中,按顺序对它们进行funcall,然后存储最终结果以符合PROGN行为)。您可以只使用PROGN,或者,由于LET包含隐式PROGN,因此只需使用反向报价机制的@功能拼接主体:

(defmacro mylet (args &body exp) `(let ,args ,(cons 'progn exp)))

(defmacro mylet (args &body exp) `(let ,args ,@exp))

谢谢,这是一个很好的答案——我从未想过使用cons+progn,我也不知道拼接。但是,我不知道你从哪里得到((打印(+AB))。。。它是否应该尝试评估(打印(+a b))?我错过了什么?即使没有dolist,像(first,exp)这样简单的东西也不起作用。我从中得到了
((print(+ab))
,这是测试宏是否扩展到您认为它们所做的事情的最好方法。rest/&body(它们是等效的,差异只对人类读者有意义)参数始终是所有剩余参数的列表,因此宏扩展时变量
exp
的值是具有打印表示形式的对象
((打印(+a b))
,按原样插入到生成的代码中。然后,代码的执行方式与键入的方式相同。哎呀,前面应该有一个“a”,这样它就被视为一个列表……但即使有,它仍然不起作用。系统不会评估随机列表,因为它们恰好看起来像代码。列表就是一个list,如果它被视为一个列表,那么它就被视为一个列表,在本例中,这意味着它被元素丢弃,因为你在DOLIST中没有对它们做任何处理。啊,好的,这是我的问题…谢谢!