为何Common Lisp中(let ((x 'huh?)) (cons (boundp 'x) x))返回(NIL . HUH?)?
核心原因:boundp 只检查**特殊变量(动态变量)**的绑定,不处理默认的词法变量
Common Lisp的变量默认是词法作用域的,你用let创建的x默认就是词法变量:
- 词法变量的存在性、绑定关系在编译/解释的词法分析阶段就已经确定,运行时不需要查询符号本身的属性,所以你直接在
cons第二个参数传x能正常取到值,不会报错。 - 而
boundp的功能是专门检查符号的动态绑定是否存在,也就是仅对声明了special的特殊变量生效,默认的词法变量根本不会在符号的动态绑定表里留下记录,所以返回NIL是完全符合设计的。
你看到的HyperSpec文档的表观矛盾,本质是术语的上下文语义差异:
词汇表和
let文档里提到的「绑定」是广义概念,既包含词法绑定也包含动态绑定;但boundp文档里的「绑定」是窄义的,专指动态绑定。
你可以自己做个测试,给let里的x加上特殊声明,boundp就会返回你预期的T:
CL-USER> (let ((x 'huh?)) (declare (special x)) (cons (boundp 'x) x)) (T . HUH?)
补充一点:Common Lisp里之所以单独做这个区分,是因为动态变量通常用来做全局配置、动态上下文传递,我们需要在运行时判断某个动态变量有没有被绑定,而词法变量的作用域是固定的,完全可以在编译期确定有没有定义,不需要专门做运行时检查。
内容的提问来源于stack exchange,提问作者kjo
相关产品推荐
相关产品推荐

