9

在 Common Lisp (SBCL 1.0.58) 中,为什么宏 OR 使用 gensym,而不使用 AND?

例如,

    CL-USER> (macroexpand '(and 1 2 3 4 5))
    (IF 1
        (AND 2 3 4 5)
        NIL)
    T
    CL-USER> (macroexpand '(or 1 2 3 4 5))
    (LET ((#:G967 1))
      (IF #:G967
          #:G967
          (OR 2 3 4 5)))
    T
    CL-USER> 

我查看了定义宏的 defboot.lisp,但在评论中没有发现任何相关内容。

4

2 回答 2

16

这是因为实现的逻辑运算符旨在短路并返回它们评估的最后一个形式产生的值。

为了实现这一点,and不需要 a gensym,因为它评估的最后一个表单将产生NIL或成为对自身的最终尾调用的结果。

另一方面,or必须返回NIL它评估的第一个非值,因此它不能依赖尾调用。它需要一个gensym来做到这一点,因为没有一个:

(IF 1
    1
    (OR 2 3 4 5))

1在展开式中出现两次,在我们的例子中,这意味着产生的表达式1被计算了两次而且你永远不想在你的宏中使用它

于 2012-08-27T19:11:49.603 回答
4

假设a是假的,但是bcd是真的。现在,由于短路,我们有:

(or  a b c d) => b
(and a b c d) => nil
(or    b c d) => b
(and   b c d) => d

如您所见,在这种AND情况下,最左边的参数的值永远不会用作表单的返回值(除非只有一个参数,在这种情况下扩展是不同的)。OR另一方面,在这种情况下,最左边的参数的值是返回值,如果它是真的。因此,AND可以在测试其真实性后丢弃该值(因此不需要将其存储在临时变量中),但OR不能。

于 2012-08-27T19:13:22.690 回答