【问题标题】:Change default reader in common lisp更改 common lisp 中的默认阅读器
【发布时间】:2015-09-11 22:36:58
【问题描述】:

我写了一些函数,可以代替普通lisp的函数read

(defun my-read (stream &rest args)
  (declare (ignore args))
  (funcall (my-get-macro-character (read-char stream))))

有没有办法将此功能用作默认阅读器?

【问题讨论】:

  • 简短回答:不,至少不是便携的。 loadcompile-file 之类的东西可能会将阅读器内联,或者它们可能引用内部阅读器定义,例如绕过可选/关键参数处理开销。

标签: stream common-lisp reader reader-macro


【解决方案1】:

你不能重新定义内置函数1,但是你可以定义一个包来隐藏cl:read并定义一个新函数my:read ,因此当您使用该软件包时,看起来它是默认的 read 功能。例如,像这样:

CL-USER> (defpackage #:my-package 
           (:use "COMMON-LISP")
           (:shadow #:read)
           (:export #:read))
;=> #<PACKAGE "MY-PACKAGE">

CL-USER> (defun my-package:read (&rest args)
           (declare (ignore args))
           42)
;=> MY-PACKAGE:READ

CL-USER> (defpackage #:another-package
           (:use #:my-package "COMMON-LISP")
           (:shadowing-import-from #:my-package #:read))
;=> #<PACKAGE "ANOTHER-PACKAGE">

CL-USER> (in-package #:another-package)
;=> #<PACKAGE "ANOTHER-PACKAGE">

ANOTHER-PACKAGE> (read)
;=> 42

  1. 实际上,就像 cmets 中的 Rainer Joswig noted 一样,即使它是未定义的行为(参见 11.1.2.1.2 Constraints on the COMMON-LISP Package for Conforming Programs),也经常有种方法来重新定义一些 Common Lisp 函数,例如,在 SBCL你可以使用unlock-package,如redefining built-in function所示。 CLISP 有package locks。其他实现可能具有类似的功能。

【讨论】:

  • 请注意,该标准不允许重新定义标准函数,但许多/大多数实际实现都有特定于实现的方式来这样做。
  • 更改默认阅读器以阅读主文件没有用
  • @cl-porky11 我不确定您所说的“主文件”到底是什么意思。如果你在某处有这样的定义,那么你需要做的就是在该文件的顶部(in-package #:my-package)
【解决方案2】:

一种方法是对可读表中的所有“有效”输入字符使用set-macro-character。 (如果只接受 ASCII 输入也可以,但我不知道这对于完整的 Unicode 是否实用。)

类似这样的:

(defun replace-default-read-behavior (rt fn)
  (loop for c across 
        " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
        do (set-macro-character c fn t rt)))

(defun my-parser (stream char)
  (format t "custom read: ~A~A" char (read-line stream)))

(defun my-get-macro-character (char)
  (declare (ignore char))
  #'my-parser)

(defun my-read (stream char)
  (funcall (my-get-macro-character char) stream char))

(defvar *my-readtable* (copy-readtable ()))

(replace-default-read-behavior *my-readtable* #'my-read)

(let ((*readtable* *my-readtable*))
  (read-from-string "foo"))
custom read: foo  ; printed
NIL               ; returned
3

【讨论】:

  • 我也想过这个解决方案,但它不适用于非标准字符,在某些情况下可能会出现问题。 (你忘记了字符串中的#\Newline)
  • @cl-porky11 同意了。最坏的情况是,意外的字符可能会导致您的程序默默地行为不端。如果您调整 my-read 以摄取整个输入,您可以放宽要求,即输入的第一个字符必须是您期望的。这仍然不令人满意,但我不知道有更好的方法来做到这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-17
  • 1970-01-01
相关资源
最近更新 更多