我正在尝试在 Lisp 中编写一个宏,使用其自身重新实现 let
。这是一个微不足道的练习,没有实际目的;然而在给出 response 之后对于一个相关的问题,我意识到我应该更多地了解宏。它们被誉为 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 (+ A B)))
不是有效的表达式。还有一个问题是,在宏扩展中使用驻留符号可能会导致变量捕获,但这并不直接相关(请参阅 PCL 了解更多信息)。
这里使用 DOLIST 是不必要的,而且要正确执行会很复杂(您必须将所有子表单转换为匿名函数,以便将它们粘贴在列表中,按顺序调用它们,然后存储最终结果以符合 PROGN行为)。您可以只使用 PROGN,或者,由于 LET 包含隐式 PROGN,因此只需使用反引号机制的 ,@ 功能来拼接主体:
(defmacro mylet (args &body exp) `(let ,args ,(cons 'progn exp)))
(defmacro mylet (args &body exp) `(let ,args ,@exp))
关于macros - Lisp 宏的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6197460/