Common Lisp(SBCL)宏中符号包名追加行为的技术问询
为什么两个宏展开后的符号包限定不同?
这个问题的核心在于Common Lisp的符号包解析规则和宏展开的上下文环境,咱们一步步拆解:
1. 包定义的基础规则
你的包定义是:
(defpackage "MY-TEST" (:use "COMMON-LISP") (:export :appended :not-appended))
这里MY-TEST包声明了:use "COMMON-LISP",这意味着:
- 在
MY-TEST包中编写代码时,未加包限定的符号会优先在COMMON-LISP(简称CL)包中查找已存在的符号。 - 如果找不到匹配的符号,就会在
MY-TEST包中创建一个新的符号。
2. 两个宏的符号解析差异
咱们看两个宏的定义:
第一个宏:not-appended
(defmacro not-appended () `(list ':type 'array))
这里的array符号,因为MY-TEST包:use了CL包,而CL:ARRAY是Common Lisp内置的标准符号,所以这个array会被解析为COMMON-LISP:ARRAY。
当你在REPL(通常默认是CL包)中调用(my-test:not-appended)时,展开后的ARRAY是CL包的符号,当前REPL环境直接认识它,所以输出时不需要额外的包限定,结果就是(:TYPE ARRAY)。
第二个宏:appended
(defmacro appended () `(list ':type 'something-else))
这里的something-else是一个全新的符号,CL包中不存在这个符号,所以按照包规则,它会被创建在MY-TEST包中,而且这个符号没有被导出(你的defpackage只导出了两个宏,没导出something-else)。
当你在CL包的REPL中调用(my-test:appended)时,展开后的SOMETHING-ELSE是MY-TEST包的未导出符号,CL包无法直接访问未导出的符号,所以必须用包限定名MY-TEST::SOMETHING-ELSE来显示,结果就是(:TYPE MY-TEST::SOMETHING-ELSE)。
3. 额外验证:在MY-TEST包中调用的结果
如果切换到MY-TEST包中调用这两个宏:
(in-package :MY-TEST) (not-appended) ; 输出 (:TYPE ARRAY) —— ARRAY还是CL包的符号 (appended) ; 输出 (:TYPE SOMETHING-ELSE) —— 当前包直接访问自己的符号,不需要限定
这就能更直观地看到包环境对符号显示的影响。
关键总结
- 宏展开的符号解析是在宏定义的包环境中完成的,不是调用时的环境。
- 未限定符号的查找优先级:先找
:use的包,再找当前包。 - 未导出的符号在其他包中访问时,必须用双冒号的包限定名显示。
内容的提问来源于stack exchange,提问作者Makketronix
相关产品推荐
相关产品推荐

