You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否修改Lisp Reader实现含多个点的列表自定义解析?

实现自定义Lisp Reader行为处理带多个点的列表输入

完全可行,你可以通过错误捕获+流回退或者自定义Reader Macro两种方式实现需求。以下是具体实现方案:

方案一:错误捕获与流调整(兼容标准语法)

这种方式仅在触发SIMPLE-READER-ERROR时介入,不改变正常Lisp代码的解析行为,适合需要兼容标准语法的场景。

核心思路是:捕获多点点号引发的读取错误,将误判为分隔符的点号放回输入流,重新将其作为普通符号读取,再继续解析剩余内容。

示例代码:

(defun custom-read (&optional (stream *standard-input*) eof-error-p eof-value recursive-p)
  (handler-bind ((simple-reader-error
                   (lambda (err)
                     ;; 匹配SBCL多点点号的错误提示(不同Lisp实现可能需调整字符串)
                     (when (search "multiple dots" (format nil "~a" err))
                       (let ((pos (file-position stream)))
                         ;; 回退流到点号之前的位置
                         (file-position stream (- pos 1))
                         ;; 安装重启选项,将点号作为普通符号处理
                         (restart-case (error err)
                           (treat-dot-as-symbol ()
                             :report "Treat the dot as a regular symbol"
                             ;; 读取点号作为符号,递归读取剩余内容构建列表
                             (let ((dot-symbol (intern "."))
                                   (rest (custom-read stream eof-error-p eof-value recursive-p)))
                               (return-from custom-read
                                 (if (consp rest)
                                     (cons dot-symbol rest)
                                     (list dot-symbol rest))))))))))
    (read stream eof-error-p eof-value recursive-p)))

使用时直接调用custom-read替代原生read,输入'(a . b . c)会返回(A . B . C),与(list 'A '|.| 'B '|.| 'C)完全等价。

方案二:自定义Reader Macro(直接修改列表解析规则)

如果不需要兼容标准的(a . b) cons语法,可以直接重新定义左括号的Reader Macro,将所有点号视为普通符号解析。

示例代码:

;; 重新定义左括号的读取宏
(set-macro-character #\(
                     (lambda (stream char)
                       (let ((items nil))
                         (loop
                           (let ((next (read-preserving-whitespace stream nil nil t)))
                             (cond
                               ((eql next #\)) ; 遇到右括号,结束解析
                                (return (nreverse items)))
                               ((eql next '|.|) ; 遇到点号,作为符号加入列表
                                (push (intern ".") items))
                               (t ; 普通元素直接加入
                                (push next items))))))
                     t)

修改后,原生read函数会直接将(a . b . c)解析为包含符号.的列表,无需额外错误处理。


内容的提问来源于stack exchange,提问作者永劫回帰

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 14:57:48