2

let我正在尝试在 Lisp 中编写一个使用自身重新实现的宏。这是一个没有实际目的的琐碎练习;然而,在回答了一个相关问题之后,我意识到我应该更多地了解宏。它们被吹捧为 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 语句不起作用。我认为这是因为我使用了两个间接级别——指的是我在宏中创建的变量。但我似乎无法弄清楚如何解决它!有任何想法吗?

4

1 回答 1

4

您的宏扩展为:

(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))
于 2011-06-01T09:37:30.840 回答