Lisp 宏的问题

发布于 2024-11-11 13:28:17 字数 672 浏览 1 评论 0原文

我正在尝试在 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)设置正确,但打印语句不起作用。我认为这是因为我使用了两个间接级别——引用我在宏中创建的变量。但我似乎不知道如何解决它!有什么想法吗?

I'm trying to write a macro in Lisp that re-implements let using itself. This is a trivial exercise which has no practical purpose; however after giving a response to a related question, I realized I should probably learn more about macros. They're touted as one of the great things about Lisp, but I rarely use them.

Anyway, here's what I tried first:

(defmacro mylet (args &rest exp) `(let ,args (dolist (x ,exp) x)))

but when I try something like:

 (mylet ((a 5) (b 2)) (print (+ a b)))

this throws up an error:

  #1=(PRINT (+ A B)) is not a symbol or lambda expression in the form (#1#) .

args (a and b) are set properly, but the print statement doesn't work. I think it's because I'm using two levels of indirection-- referring to a variable that I've created within the macro. But I can't seem to figure out how to fix it! Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦里的微风 2024-11-18 13:28:17

您的宏扩展为:

(LET ((A 5) (B 2))
  (DOLIST (X ((PRINT (+ A B)))) X))

这是无效的,因为 ((PRINT (+ AB))) 不是有效的表达式。还有一个问题是,在宏扩展中使用 interned 符号可能会导致变量捕获,但这并不直接相关(请阅读 PCL)。

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

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

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

Your macro expands to:

(LET ((A 5) (B 2))
  (DOLIST (X ((PRINT (+ A B)))) X))

which is invalid because ((PRINT (+ A B))) is not a valid expression. There is also an issue that using an interned symbol in macro expansion can lead to variable capture, but that is not directly relevant (read more in PCL).

Using DOLIST here is unnecessary, and compilcated to get right (you would have to convert all subforms to anonymous function in order to stick them in a list, funcall them in sequence and then store the final result in order to conform to PROGN behaviour). You can just use PROGN, or, since LET includes an implicit PROGN, just splice the body using the ,@ feature of backquote mechanism:

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

(defmacro mylet (args &body exp) `(let ,args ,@exp))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文