背景

bound是bind的过去分词,bind是绑定的意思,bound就是已经绑定。

绑定在lisp中的意思,就是某个“符号”是否与一个值相对应,或者说,某个“符号”是否代表着某个值。

发送给lisp解释器interpreter的所有代码,会当作一系列“符号”来处理,interpreter会判断这些“符号”是否与某个值绑定, 绑定了就用那个值去替换那个符号,这就是求值eval的过程。

基于前述的eval过程的原理,lisp interpreter都会维护1个符号表,记录当前已经定义的符号,以及符号对应的值。

如何查看当前定义了哪些符号呢?

有1个专门的函数可以达到这个目的:atoms-family,这个函数会返回当前已经定义所有符号。不同的lisp实现, 可能对于这个功能的函数有不同的命名,不过,通常都会提供1个拥有相同功能或者类似功能的这么样的一个函数。

boundp函数是干啥的

根据autocad的官方帮助文档boundp函数接受1个符号作为入参,功能是“Verifies if a value is bound to a symbol”, 意思是“判断1个符号是否绑定了1个值”,它的返回值为tnil

t是经典(传统、老派)lisp语言的真值,相当于其他编程语言中的boolean型的truenil则对应于false。 某些新的lisp实现、某些lisp方言以及lisp的最大、最主流的变种scheme,把tnil改成了#t#f#t又可以写作#true#f又可以写作#false

官方文档关于返回值的更进一步的说明,有3句话。

  1. T if sym has a value bound to it.
    如果那个符号绑定了某个值,那么就返回t

  2. If no value is bound to sym, or if it has been bound to nil, boundp returns nil.
    如果那个符号没有绑定任何值,或者,绑定的值是nil,那么返回值就是nil

  3. If sym is an undefined symbol, it is automatically created and is bound to nil.
    如果那个符号是未定义(其他编程语言中的未声明)的符号,那么,解释器会自动创建(声明)那个符号, 并将它绑定(赋值)到nil值。

到这里,boundp的功能就很明确了。

简单来讲,在调用1次boundp函数之后,1个没有身份的变量,从此就有了身份。因为,它从此就被定义了,就进入了符号表了。

boundp的异常行为

在autolisp中,直到AutoCAD 2023版,boundp函数,它的行为依然与官方文档的描述不相符。这里的“不相符”的意思是, 调用boundp之后,原先不存在的符号,依然无法通过atoms-family检索出来,仍然不存在。

所以,这就有了2种可能性,

  1. boundp有bug,
  2. atoms-family有bug。

我更倾向于第1种可能,因为,atoms-family的bug更加令人无法接受,作为1个快40年历史的编程语言来说,不太可能在atoms-family 这种非常底层的函数上留存bug。

到底是boundp异常还是interpreter出错

boundp函数这个奇怪的表现,我在autocad官方论坛发帖反映之后,收到了很多脑残回复。小部分人在劝我不要纠结这个问题, 其余的占大部分比例的回复的意思都是把这个当做autolisp解释器的1个feature特性,这是我总结之后的说法, 那些脑残的原话并不是这样的,不过,意思就是这么个意思。

那么,这个所谓的feature到底是什么呢?

就是vm虚拟机在不该gc的时候,做了gc,把一部分有户口的变量直接干成了黑户。

为什么会是这个样子呢?

因为,对于lisp来说,任何符号(变量)只有2种值,nil值(假值、falsenullvoidundefined) 和非nil值(真值、t、各种其他值),vm做gc把nil值清理掉,这似乎是合情合理的做法。

然而,这种激进的gc策略,其实是错误的做法,完全不符合lisp解释器的工作原理。

因此,把boundp的这种异常行为解释成autocad的autolisp解释器的feature,这种说法是说不通的, 因为解释器根本不可能设计成这个样子。其他的autolisp解释器,比如zwcad中望cad,boundp就是按照预期的方式在工作的, 原本无法从atoms-family返回值中查询到的符号,使用boundp之后就能够查询到了。

结论

综上,与其相信autocad的autolisp解释器有问题,或者,这个解释器具有与众不同的特殊的feature, 我更愿意相信是某个内置函数存在bug,比如boundp函数。

为什么不能是atoms-family函数有问题呢?前面已经说过了,atoms-family函数本质上和boundp是一个层级(等级)的底层函数, 但是,boundp的具体实现有可能是依赖于atoms-family做出来的,从实际操作层面上讲,atoms-family可能比boundp更加底层 更加接近于解释器。

基于“解释器不太可能出错”、“不允许解释器出错了几十年而不去解决”这样的大前提,只能是boundp存在着bug却长期没有得到修复。