gpt4 book ai didi

macros - 一次性 lisp 宏,我的实现是否正确?

转载 作者:太空宇宙 更新时间:2023-11-03 18:46:50 28 4
gpt4 key购买 nike

我正在尝试从 Peter Seibel 的《Practical Common Lisp》一书中学习 Lisp。在 chapter 8 : "Macros: Defining your own" ,我遇到了这个一次性的宏。在该页面的底部,给出了一个实现。现在这对我来说是一个非常复杂的宏,所以我看到了 this question on stackoverflow那里有一些很好的解释。

然而,即使我(仍然)没有完全理解这个宏,我也理解它的目的。所以我尝试编写自己的实现:

(defmacro my-once-only ((&rest names) &body body)
(let
(
(gensyms (loop for n in names collect (gensym)))
)

`(list 'let
(list ,@(loop for n in names for g in gensyms collect `(list ',g ,n)))

(let
,(loop for n in names for g in gensyms collect `(,n ',g))

,@body))))

(如果我没有遵循标准的 lisp 缩进约定,请原谅我,我试图以某种方式缩进代码,以便我可以理解什么地方去了,因为我是新手)

我测试这个宏的方式与我链接的那一章中描述的方式大致相同,即。使用像 (random 100) 这样的参数调用函数,这样如果它们被计算两次,结果将是错误的。我还通过 macroexpand/macroexpand-1 扩展了我的宏(以及我在其中使用的宏),这似乎也是正确的。

所以我想知道我的实现是否正确?还是我遗漏了什么(我想这很可能)...

最佳答案

让我们实际宏展开这两个实现,看看它们有何不同:

* (macroexpand '(once-only (foo bar) (+ foo bar)))
(LET ((#:G619 (GENSYM)) (#:G620 (GENSYM)))
`(LET ((,#:G619 ,FOO) (,#:G620 ,BAR))
,(LET ((FOO #:G619) (BAR #:G620))
(+ FOO BAR))))

* (macroexpand '(my-once-only (foo bar) (+ foo bar)))
(LIST 'LET (LIST (LIST '#:G621 FOO) (LIST '#:G622 BAR))
(LET ((FOO '#:G621) (BAR '#:G622))
(+ FOO BAR)))

让我们将您的宏展开式重写为 Lisper 更容易阅读的内容:

`(LET ((#:G621 ,FOO) (#:G622 ,BAR))
,(LET ((FOO '#:G621) (BAR '#:G622))
(+ FOO BAR)))

请注意,您的版本缺少附加 gensym 的间接寻址。这意味着每次调用外部宏(使用 my-once-only 的宏)每次都使用相同的符号。如果您的宏调用嵌套(例如,您在另一个使用外部宏的主体内使用外部宏),符号将发生冲突。

关于macros - 一次性 lisp 宏,我的实现是否正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23232156/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com