为何Lisp读取器宏处理[1,2,3]返回(LIST 1 2 3)而非(1 2 3)?
关于Lisp读取器宏返回
(LIST 1 2 3)而非(1 2 3)的疑问 我为深入理解Lisp读取器宏,参考文章改编代码,意图将JSON格式数组[1,2,3]读取为Lisp列表(1 2 3)。测试代码执行后得到(LIST 1 2 3),而非预期结果。但全局设置读取表后在REPL输入[1,2,3]却能得到(1 2 3),直接读取字符串"(1 2 3)"也符合预期。
修改read-left-bracket函数为直接收集对象后,读取行为恢复正常。想请教:为何出现这种差异?是否存在隐藏的eval操作?
原测试代码
(with-input-from-string (stream "[1,2,3]") (let ((*readtable* (copy-readtable))) (set-macro-character #\[ 'read-left-bracket) (set-macro-character #\] 'read-delimiter) (read stream)))
修改后的read-left-bracket函数
(defun read-left-bracket (stream char) (declare (ignore char)) (let ((*readtable* (copy-readtable))) (set-macro-character #\, 'read-separator) (loop for object = (read-next-object #\, #\] stream) while object collect object)))
解答
首先明确:Lisp的read函数本身不会执行eval,它仅负责将输入解析为Lisp对象(S表达式)。
你最初的read-left-bracket函数应该是返回了(LIST 1 2 3)这样的列表(即以LIST为第一个元素的cons结构),而非直接返回元素组成的列表。read会直接将读取器宏函数返回的对象作为解析结果输出——除非该对象是特殊的读取器宏展开形式(如(quote ...))。
而全局设置读取表后在REPL输入时,REPL的行为是read之后自动执行eval,所以(LIST 1 2 3)会被求值为(1 2 3);但你的局部测试代码仅调用了read,没有后续的eval步骤,因此得到的是read解析后的原始对象(LIST 1 2 3)。
修改后的read-left-bracket函数直接收集元素并返回(1 2 3)这个列表,read返回的就是该列表,无需额外eval就符合预期。
核心差异点:
- 局部测试仅执行
read,返回解析后的S表达式本身 - REPL会自动在
read后执行eval,将(LIST ...)求值为实际列表 - 不存在隐藏的
eval,只是REPL的默认行为包含了eval步骤,而你的测试代码没有
内容的提问来源于stack exchange,提问作者nosejose
相关产品推荐
相关产品推荐

