我正在阅读On Lisp,不明白为什么下面的代码使用引号。以下是文本摘录:
为用户保留的另一个字符组合是#[。图17.3给出了如何将此字符定义为精心设计的左括号。它定义了form#[xy]读取为x和y之间的所有整数的列表,包括:
#[2 7] (2 3 4 5 6 7)
图17.3:定义分隔符的读取宏
(set-macro-character #] (get-macro-character #))) (set-dispatch-macro-character ## #[ #'(lambda (stream char1 char2) (let ((accum nil) (pair (read-delimited-list #] stream t))) (do ((i (ceiling (car pair)) (1+ i))) ((> i (floor (cadr pair))) (list 'quote (nreverse accum))) (push i accum))))) Figure 17.3: A read-macro defining delimiters.
我不明白为什么do**的结果形式中的行是**(list'quote(nrevere-accum))而不是(nrevery-accum) 有人知道这里的诀窍吗?(let ((acc nil))
(do ((i 2 (1+ i)))
((> i 7)
(nreverse acc))
(push i acc)))
如果在Lisp侦听器中输入新语法,读取器将返回一个数字列表。评估这个数字列表将是一个错误,因为Lisp期望函数或宏作为列表的头。列表不是以向量、数字、哈希表等形式对自己求值。。。是
因此,您有两个选择:
- 让用户在间隔表达式前面写一个引号,以防止求值
- 返回带引号的列表
在这里我们看到选择2。
CL-USER 7 > (read-from-string "#[5 10]")
(QUOTE (5 6 7 8 9 10))
CL-USER 8 > (eval (read-from-string "#[5 10]"))
(5 6 7 8 9 10)
CL-USER 9 > (let ((e #[5 10]))
(describe e))
(5 6 7 8 9 10) is a LIST
0 5
1 6
2 7
3 8
4 9
5 10
如果阅读器宏不返回报价表,我们将不得不写:
CL-USER 10 > (let ((e '#[5 10])) ; notice the QUOTE
(describe e))
(5 6 7 8 9 10) is a LIST
0 5
1 6
2 7
3 8
4 9
5 10
嗯,实际上我个人更喜欢后者,必须明确地写下引文。
我得到:
CL-USER 17 > '(#[5 10] #[20 25])
((QUOTE (5 6 7 8 9 10)) (QUOTE (20 21 22 23 24 25)))
但我更喜欢:
CL-USER 18 > '(#[5 10] #[20 25])
((5 6 7 8 9 10) (20 21 22 23 24 25))