4

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

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

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

4

2 回答 2

5

您不能重新定义内置函数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. 实际上,正如Rainer Joswig在评论中指出的那样,即使它是未定义的行为(参见11.1.2.1.2 Constraints on the COMMON-LISP Package for Conforming Programs),通常一些方法可以重新定义一些 Common Lisp 函数,例如,在 SBCL 中,您可以使用unlock-package,如重新定义内置函数所示。CLISP 有包锁。其他实现可能具有类似的功能。
于 2015-06-25T11:25:08.550 回答
3

一种方法是对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
于 2015-06-25T23:05:22.273 回答