【问题标题】:In Common Lisp why does the macro OR use a gensym, but not AND?在 Common Lisp 中,为什么宏 OR 使用 gensym,而不使用 AND?
【发布时间】:2012-08-22 06:57:52
【问题描述】:

在 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,但在 cmets 中没有发现任何相关内容。

【问题讨论】:

    标签: macros lisp common-lisp sbcl


    【解决方案1】:

    这是因为实现的逻辑运算符旨在为 short-circuiting 并返回它们评估的最后一个表单产生的值。

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

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

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

    1 在展开式中出现两次,在我们的例子中,这意味着产生1 的表达式被计算两次And you never want that in your macros.

    【讨论】:

    • 是的,我现在明白了。谢谢。
    【解决方案2】:

    假设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 不能。

    【讨论】:

      猜你喜欢
      • 2010-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-18
      • 2011-03-20
      • 1970-01-01
      • 2019-01-18
      • 2019-04-26
      相关资源
      最近更新 更多