2013-09-02 39 views
6

Tại sao những điều sau đây không hoạt động?Tại sao không đọc phần mở rộng macro phổ biến để chạy (đọc)?

;;;; 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) 

thì:

LISP> (load (compile-file "foo.lisp")) 
=> T 

LISP> (read-and-eval 
     "(let ((a \"foo\")) (prinC#?\"${a}\"))") 
=> no dispatch function defined for #\? 

Trả lời

8

CL: ĐỌC công văn dựa trên ràng buộc có thể đọc được tới CL: * READTABLE * tại thời điểm cuộc gọi đến READ chạy. Dưới mui xe ENABLE-INTERPOL-SYNTAX đang tạo ra một readtable mới, thiết lập CL: * READTABLE * để giữ nó, và stashing giá trị cũ của CL: * READTABLE *. DISABLE-INTERPOL-SYNTAX không hủy bỏ cài đặt có thể đọc trước đó và thiết lập CL: * READTABLE * để giữ lại nó. Tối thiểu thay đổi thiết lập ban đầu của bạn, bạn có thể sắp xếp cho hành vi mà bạn muốn bằng cách sau:

(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)))) 

Cuộc gọi để vô hiệu hóa cú pháp có thể được đặt ở bất cứ đâu sau khi defvar và đọc-và-eval sẽ vẫn làm việc, nhưng nếu bạn muốn nhập trực tiếp cú pháp interpol vào tệp mà cú pháp sẽ phải được đặt giữa các cuộc gọi bật và tắt. Với mục đích thứ hai, điều quan trọng là interpol gọi mở rộng thành EVAL-WHENs, vì cùng một lý do là cần thiết cho cuộc gọi của bạn đến REQUIRE để ở trong EVAL-WHEN; đó là, các hiệu ứng cần phải đã xảy ra khi các dạng sau được ĐỌC. giao diện

CL-INTERPOL của tóm tắt những gì đang xảy ra, vì vậy tôi sẽ chỉ cho bạn cách bạn tự có thể tạo và thay đổi một readtable:

;; 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) 
10

Bởi vì chỉ có một độc giả duy nhất, với trạng thái toàn cầu. Bạn đang bật và tắt macro hiệu quả. Trong trường hợp này, các macro trình đọc chỉ được bật trong khoảng thời gian mà hàm read-and-eval của bạn được đọc vào thời gian biên dịch.

Trong trường hợp này, bạn cần thiết lập các macro trong hàm read-and-eval để đảm bảo người đọc ở trạng thái thích hợp khi bạn cần.

Các vấn đề liên quan