Необходимость цитаты в On Lisp's #[ read macro?
Я читаю на Лиспе и не могу понять, почему в приведенном ниже коде используется кавычка. Вот выдержка из текста:
Другая комбинация символов, зарезервированная для пользователя, это # [. На рисунке 17.3 приведен пример того, как этот символ может быть определен как более сложный вид левой скобки. Он определяет выражение в форме #[x y] для чтения в виде списка всех целых чисел от 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** это **(список 'цитата (nreverse аккумулятор))), а не (nreverse аккумулятор). Потому что мы можем без проблем запустить код, который не использует приведенную ниже цитату, верно?
(let ((acc nil))
(do ((i 2 (1+ i)))
((> i 7)
(nreverse acc))
(push i acc)))
Кто-нибудь знает трюк здесь?
1 ответ
Если вы введете новый синтаксис в прослушивателе 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))