Common lisp 为什么一个符号宏会得到一个同名的环绕let绑定的类型?

Common lisp 为什么一个符号宏会得到一个同名的环绕let绑定的类型?,common-lisp,sbcl,Common Lisp,Sbcl,SBCL中的Macroexpand all提供了以下扩展: (SB-CLTL2:MACROEXPAND-ALL '(LAMBDA (A B) (DECLARE ((SIGNED-BYTE 4) A)) (+ A B (SYMBOL-MACROLET ((A 1) (B 2)) (+ A B))))) => (LAMBDA (A B) (DECLARE ((SIGNED-BYTE 4) A)) (+ A B (SY

SBCL中的Macroexpand all提供了以下扩展:

(SB-CLTL2:MACROEXPAND-ALL
 '(LAMBDA (A B)
   (DECLARE ((SIGNED-BYTE 4) A))
   (+ A B
    (SYMBOL-MACROLET ((A 1) (B 2))
      (+ A
         B)))))    
=>
(LAMBDA (A B)
  (DECLARE ((SIGNED-BYTE 4) A))
  (+ A B
     (SYMBOL-MACROLET ((A 1) (B 2))
       (+ (THE (SIGNED-BYTE 4) 1)
          2))))
(LAMBDA (A B)
  (DECLARE ((SIGNED-BYTE 4) A))
  (DECLARE ((SIGNED-BYTE 4) B))
  (+ A B
     (SYMBOL-MACROLET ((A 1) (B 2))
       (+ (THE (SIGNED-BYTE 4) 1) (THE (SIGNED-BYTE 4) 2)))))
为什么
A
扩展到
(有符号字节4)1
,而不仅仅是
1

我知道这来自
(声明((有符号字节4)A))
, 但这是否会影响SYMBOL-MACROLET

这难道不应该是合法的吗 扩展到非
(带符号字节4)

免责声明我不知道这是否真的回答了问题。欢迎评论和编辑。

悬而未决的问题 正如Dirk在评论中所说,在Common Lisp中,这种语言被认为是(专门用于
declare
form())的部分):

symbol macrolet
有一些特有的方面。[…]一种类型 由symbol macrolet定义的名称声明在 将提及该类型的
表单包装在
已定义符号的扩展

据我所知,这个问题有些争议,例如,它似乎是一个公开的问题这是强制性的还是不强制性的?请阅读以下内容:

[…]必须(或可能)由宏扩展或 如果存在 是否应用于正在展开的符号宏

有四个建议,可能,以及可能。在我上面链接的文章中阅读有关它们的内容。这四项建议中的每一项都有一个理由

SBCL可以做到这一点。我认为这是实现者的选择。

为什么??嗯,是的的基本原理给出了一个理由


有一些优点(?) 例如,对编译器来说,代码的优化可能更“容易”。看看这个

无声明,无扩展中的
: 拿这个来说:

(SB-CLTL2:MACROEXPAND-ALL
          '(LAMBDA (A B)
            (+ A B
             (SYMBOL-MACROLET ((A 1) (B 2))
               (+ A B)))))
结果很简单:

(LAMBDA (A B)
  (+ A B
     (SYMBOL-MACROLET ((A 1) (B 2))
       (+ 1 2))))
如果您将后者放在一个非常想优化的文件中,可以这样说:

(declaim (optimize (speed 3) (debug 0) (safety 0)))
; note: forced to do GENERIC-+ (cost 10)
;       unable to do inline fixnum arithmetic (cost 1) because:
;       The first argument is a NUMBER, not a FIXNUM.
;       The result is a (VALUES NUMBER &OPTIONAL), not a (VALUES FIXNUM &REST T).
;       unable to do inline fixnum arithmetic (cost 2) because:
;       The first argument is a NUMBER, not a FIXNUM.
;       The result is a (VALUES NUMBER &OPTIONAL), not a (VALUES FIXNUM &REST T).
;       etc.
编译后,SBCL会给你一系列警告,如下所示:

(declaim (optimize (speed 3) (debug 0) (safety 0)))
; note: forced to do GENERIC-+ (cost 10)
;       unable to do inline fixnum arithmetic (cost 1) because:
;       The first argument is a NUMBER, not a FIXNUM.
;       The result is a (VALUES NUMBER &OPTIONAL), not a (VALUES FIXNUM &REST T).
;       unable to do inline fixnum arithmetic (cost 2) because:
;       The first argument is a NUMBER, not a FIXNUM.
;       The result is a (VALUES NUMBER &OPTIONAL), not a (VALUES FIXNUM &REST T).
;       etc.
通过声明,SBCL将放在扩展中: 现在试试这个:

(SB-CLTL2:MACROEXPAND-ALL
          '(LAMBDA (A B)
            (DECLARE ((SIGNED-BYTE 4) A))
            (declare ((signed-byte 4) B))
            (+ A B
             (SYMBOL-MACROLET ((A 1) (B 2))
               (+ A B)))))
这是扩展:

(SB-CLTL2:MACROEXPAND-ALL
 '(LAMBDA (A B)
   (DECLARE ((SIGNED-BYTE 4) A))
   (+ A B
    (SYMBOL-MACROLET ((A 1) (B 2))
      (+ A
         B)))))    
=>
(LAMBDA (A B)
  (DECLARE ((SIGNED-BYTE 4) A))
  (+ A B
     (SYMBOL-MACROLET ((A 1) (B 2))
       (+ (THE (SIGNED-BYTE 4) 1)
          2))))
(LAMBDA (A B)
  (DECLARE ((SIGNED-BYTE 4) A))
  (DECLARE ((SIGNED-BYTE 4) B))
  (+ A B
     (SYMBOL-MACROLET ((A 1) (B 2))
       (+ (THE (SIGNED-BYTE 4) 1) (THE (SIGNED-BYTE 4) 2)))))
把后者放在一个文件中,把优化的宣言,编译。你猜怎么着?没有警告。SBCL不再抱怨无法对代码进行硬核心优化。它能做到。由于
(有符号字节4)1)
部分


因此,也许这是一种确保类型声明也会影响macrolet表单中的变量的方法,提供类型检查,并增强编译器优化代码的能力?在Common Lisp中,
let
符号macrolet
阴影词法绑定,以及
(声明((有符号字节4)a))
是一个绑定声明,因此如果SBCL所做的是将声明传播到隐藏绑定,则这是一个错误

此示例可能会更清楚地说明这一点(这不是一个好的做法,但它可以达到以下目的):

第二个
a
绑定将第一个绑定隐藏起来,因此第一个绑定在第二个绑定的范围内变得不可访问

第二个
a
没有任何类型声明,并且它不应该继承以前使用相同名称的词汇绑定的任何类型声明。词法绑定的类型声明应该仅应用于该特定绑定,而不管其名称如何

因此,
macroexpand all
的输出形式不应该有一个
a
包装对第二个
a
的访问,至少一个显然来自第一个绑定。也就是说,编译器可能足够聪明,可以看到第二个
a
始终是字符串,因此它可能会将其声明为字符串

以下示例仅使用
let
symbol macrolet
执行阴影操作:

(let ((a 1))
  (declare (type fixnum a))
  (symbol-macrolet ((a "1"))
    a))

(symbol-macrolet ((a 1))
  (declare (type fixnum a))
  (let ((a "1"))
    a))

(symbol-macrolet ((a 1))
  (declare (type fixnum a))
  (symbol-macrolet ((a "1"))
    a))

嗯,我能找到的最接近的东西是“允许使用与LET完全相同的声明,但有一个例外:如果特殊声明将定义为符号宏LET的符号之一命名为符号宏LET,则SYMBOL-MACROLET将发出错误信号。其中一个符号的类型声明相当于将表达式包装在该符号扩展的周围。”(from),但我并不认为这是相关的(特别是,我在CLHS中找不到这种语言).根据CLHS,我认为投票结果是
选项。但是,我没有看到明确的参考资料证明这一点,只是在CLHS中指向问题页面的超链接中,添加了标签
:否
,作为实际决定……无论如何,这在技术上是ANSI标准中的一个“缺陷”。