如何将双单引号引用的Common Lisp符号转换为字符串
双重引用形式的本质
按照Common Lisp的求值规则,''hello完全等价于(quote (quote hello))。对这个形式求值后,得到的并非直接绑定到某个值的HELLO符号,而是一个固定结构的两元素列表:
- 列表首元素是全局保留符号
COMMON-LISP:QUOTE - 列表第二个元素才是原本要定位的目标符号
HELLO
这也是直接执行(string ''hello)会触发报错的核心原因:string函数仅接受字符串、符号、字符这类合法的字符串设计符,传入列表本身就不符合参数类型要求。
可以在REPL里直接验证这个结构:
;; 查看''hello的实际求值结果 CL-USER> ''hello '(quote hello) ;; 查看返回值的实际类型 CL-USER> (type-of ''hello) CONS
报错信息的迷惑性解释
SBCL抛出的'HELLO is not a string designator看起来容易误导人,本质是SBCL在构造报错文本时,会把非法参数按人类可读的标准格式打印:代表(QUOTE HELLO)的列表,其标准可读打印形式就是'HELLO,所以报错文本直接嵌入了这个打印结果,并非真的检测到一个带单引号的特殊符号类型。
正确的转换方式
因为双重引用形式求值后是固定结构的列表,只要取出列表中代表目标符号的元素,再结合已经掌握的symbol-name/string方法做转换即可,最稳妥的写法是直接结构化取数:
;; 取出列表第二个元素,直接传入string转换 CL-USER> (string (second ''hello)) "HELLO"
注意:虽然临时在REPL里写
(string (eval ''hello))也能得到相同结果,但这种方式仅适合快速测试场景。eval会对传入的形式做完整求值,如果列表中嵌套了带副作用的计算逻辑,会触发不可预期的代码执行,正式开发场景下不要依赖eval做这类固定结构的解析。
内容的提问来源于stack exchange,提问作者Flux
相关产品推荐
相关产品推荐

