Lisp 为什么不';t读取器宏扩展是否传播到运行时(读取)?

Lisp 为什么不';t读取器宏扩展是否传播到运行时(读取)?,lisp,common-lisp,reader-macro,Lisp,Common Lisp,Reader Macro,为什么下面的方法不起作用 ;;;; foo.lisp (in-package :cl-user) (eval-when (:compile-toplevel :load-toplevel :execute) (require :cl-interpol)) (cl-interpol:enable-interpol-syntax) (defun read-and-eval (s) (eval (read-from-string s))) (cl-interpol:disable-in

为什么下面的方法不起作用

;;;; foo.lisp
(in-package :cl-user)

(eval-when (:compile-toplevel :load-toplevel :execute)
  (require :cl-interpol))

(cl-interpol:enable-interpol-syntax)

(defun read-and-eval (s)
  (eval (read-from-string s)))

(cl-interpol:disable-interpol-syntax)
然后:


因为只有一个读卡器,具有全局状态。您正在有效地打开和关闭宏。在这种情况下,读卡器宏仅在编译时读取
read and eval
函数期间启用


在这种情况下,您需要在
read and eval
函数中设置宏,以确保读卡器在需要时处于正确的状态。

CL:read调度基于绑定到CL:*readtable*的可读表,此时read调用正在运行。在引擎盖下ENABLE-INTERPOL-SYNTAX正在创建一个新的readtable,将CL:*readtable*设置为保存它,并保存CL:*readtable*的旧值。DISABLE-INTERPOL-SYNTAX正在取消上一个readtable的灰化,并将CL:*readtable*设置为再次保留它。通过对原始设置进行最小程度的更改,您可以通过以下方式安排所需的行为:

(in-package :cl-user)

(eval-when (:compile-toplevel :load-toplevel :execute)
  (require :cl-interpol))

(cl-interpol:enable-interpol-syntax)

(defvar *interpol-reader* *readtable*)

(cl-interpol:disable-interpol-syntax)

(defun read-and-eval (s)
  (let ((*readtable* *interpol-reader*))
    (eval (read-from-string s))))
禁用语法的调用可以放在defvar之后的任何位置,read和eval仍然可以工作,但是如果您想在文件中直接输入interpol语法,则必须将该语法放在enable和disable调用之间。出于后一个目的,国际刑警组织的呼叫扩展到EVAL WHEN具有重要意义,原因与您的呼叫需要在EVAL-WHEN范围内的原因相同;也就是说,在读取后一种形式时,效果必须已经发生

CL-INTERPOL的界面抽象了正在发生的事情,因此我将向您展示如何手动创建和更改可读表:

;; Create a fresh readtable with standard syntax
(defvar *not-readtable* (copy-readtable nil))

;; A simple reader function
(defun not-reader (stream char &optional count)
  "Like ' but for (not ...) instead of (quote ...)"
  (declare (ignore count char))
  `(not ,(read stream t nil t)))

;; Mutate that readtable so that the dispatch character you want
;; calls the function you want
(set-macro-character #\! 'not-reader nil *not-readtable*)

;; Try it out
(let ((*readtable* *not-readtable*))
  (read-from-string "(if !foo bar baz)"))

=>
(IF (NOT FOO)
    BAR
    BAZ)
;; Create a fresh readtable with standard syntax
(defvar *not-readtable* (copy-readtable nil))

;; A simple reader function
(defun not-reader (stream char &optional count)
  "Like ' but for (not ...) instead of (quote ...)"
  (declare (ignore count char))
  `(not ,(read stream t nil t)))

;; Mutate that readtable so that the dispatch character you want
;; calls the function you want
(set-macro-character #\! 'not-reader nil *not-readtable*)

;; Try it out
(let ((*readtable* *not-readtable*))
  (read-from-string "(if !foo bar baz)"))

=>
(IF (NOT FOO)
    BAR
    BAZ)