一次性lisp宏,我的实现正确吗? [英] once-only lisp macro, is my implementation correct?

查看:119
本文介绍了一次性lisp宏,我的实现正确吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从Peter Seibel的书"Practical Common Lisp"中学习Lisp.在第8章:宏:定义自己的" ,我遇到了这个一次性宏.在该页面的底部,给出了一个实现.现在,这对我来说是一个非常复杂的宏,因此我看到了这关于stackoverflow的问题,那里有一些很好的解释.

I am trying to learn Lisp from Peter Seibel's book "Practical Common Lisp". In chapter 8 : "Macros: Defining your own", I came across this once-only macro. At the bottom of that page, an implementation is given. Now that is a pretty complicated macro to understand for me, so I saw this question on stackoverflow and there are some good explanations there.

但是,即使我(仍然)还没有完全理解宏,我也了解了它的用途.因此,我尝试编写自己的实现:

However, even if I (still) havent fully understood the macro, I understood its purpose. So I tried to write my own implementation of it :

(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约定,请原谅我,我正在尝试以某种方式对代码进行缩进,因为我是新手,所以我可以理解该怎么做)

(Please forgive me if I am not following standard lisp conventions of indentation, I was trying to indent the code in a way so I can understand what goes where, since I am new to this)

我测试该宏的方式与我所链接的那章所述的方法大致相同.用(随机数100)之类的参数调用该函数,以便如果对它们进行两次评估,结果将是错误的.我还通过macroexpand/macroexpand-1扩展了我的宏(以及我在其中使用的宏),这似乎也是正确的.

I tested this macro much the same way as is described in that chapter I linked, ie. calling the function with arguments like (random 100) so that if they are evaluated twice, results will be wrong. I also expanded my macro (and the macro I used it in) via macroexpand/macroexpand-1 and that seems to be correct too.

所以我想知道我的实现是否正确?还是我缺少某些东西(可能是我想的)...

So I was wondering if my implementation is correct ? or is there something I am missing (which is likely I think)...

推荐答案

让我们实际对这两种实现进行宏扩展,看看它们有何不同:

Let's actually macroexpand the two implementations and see how they differ:

* (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's rewrite your macroexpansion to something easier for a Lisper to read:

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

请注意,您的版本缺少带有附加gensym的间接引用.这意味着外部宏的每次调用(使用my-once-only的宏)每次都使用相同的符号.如果您的宏调用nest(例如,您将外部宏用于另一种外部宏的主体内),则符号会发生冲突.

Notice that your version lacks the indirection with the additional gensym. That means each invocation of your outer macro (the one that is using my-once-only) is using the same symbols each time. If your macro calls nest (e.g., you use your outer macro inside the body of another use of the outer macro), the symbols will collide.

这篇关于一次性lisp宏,我的实现正确吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆