免责声明我不知道这是否真的回答了这个问题。欢迎评论和编辑。
一个开放的问题
正如 Dirk 在评论中所说,在 Common Lisp 语言中说(专用于declare
表单的部分(链接)):
有一些特殊的方面symbol-macrolet
。[..] 定义名称的类型声明by symbol-macrolet
实际上等同于将the
提及该类型的表单包装在已定义符号的扩展周围。
据我所知,这个问题有些争议,例如它似乎是一个未解决的问题。是强制的还是不强制的? 在这里阅读:
发布 SYMBOL-MACROLET-TYPE-DECLARATION 说明
[..] 如果存在适用于扩展符号宏的类型声明,则 MACROEXPAND 或 MACROEXPAND-1 返回的值是否必须(或可能)包含 THE 形式?
有四个提议,YES、NO、MAYBE和PROBABLY。在我上面链接的文章中阅读它们。这四个提案中的每一个都有一个基本原理。
SBCL 这样做。我认为这是实施者的选择。
为什么?好吧,YES的理由给出了一个理由。
有一些优点(?)
例如,对于编译器来说,代码的优化可能更“容易”一些。检查这个。
没有声明,没有the
在扩展中:
拿着这个:
(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)))
然后你编译它,SBCL 会给你一堆这样的警告:
; 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.
通过声明,SBCLthe
进行了扩展:
现在试试这个:
(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)))))
这是扩展:
(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 不再抱怨无法对您的代码进行一些核心优化。它可以做到。因为(THE (SIGNED-BYTE 4) 1)
部分。
更多关于the special form
因此,也许这是一种确保您的类型声明也会影响宏形式中的变量,提供类型检查并强制编译器优化代码的能力的方法?