macros - Lisp 宏的问题

标签 macros lisp common-lisp mcl

我正在尝试在 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/

相关文章:

c - 在将宏作为参数传递给另一个宏之前,按值转换宏

emacs - 我如何改进 Emacs Lisp Intro 的 "create index entries"练习的解决方案?

lisp - S 表达式和跟踪源位置

emacs - 在 Emacs Inferior Lisp 中读取用户输入

macros - 宏在 Notepad++ 中无法按预期工作

macros - 如何注释 VIM 宏

lisp - Audacity - 如何设置 Nyquist Prompt 控制速率以匹配音频速率?

list - 计算 LISP 中每个级别的子列表

lisp - 如何将最大值导入 sbcl

c - 如何将参数传递给可变参数宏?