Вот диаграмма, которая представляет символ a
и его значение после (setq a '(1 2))
. Поля - это элементарные структуры данных (символы и конусы), а стрелки - указатели (где одна часть данных ссылается на другую). (Я немного упрощаю.)
symbol cons cons
+-------+----------+ +------+------+ +------+------+
|name: |variable: | |car: |cdr: | |car: |cdr: |
| a | | | | 1 | | | | 2 | nil |
+-------+----|-----+ +------+--|---+ +------+------+
| ↑ | ↑
+-------------+ +-------+
Выражение '(1 2)
строит два конуса справа, которые составляют список из двух элементов. Выражение (setq a '(1 2))
создает символ a
, если он не существует, а затем заставляет его «переменную ячейку» (часть, которая содержит значение символа) указывать на вновь созданный список. setq
является встроенным макросом, а (setq a '(1 2))
является сокращением для (set 'a '(1 2))
. Первый аргумент set
- это символ, который нужно изменить, а второй аргумент - это значение, которое нужно установить для слота переменной символа.
(add-to-list 'a 3)
эквивалентно (set 'a (cons 3 a))
здесь, потому что 3 нет в списке. Это выражение делает четыре вещи:
- Создать новую ячейку минусов.
- Установите поле машины новой ячейки против на
3
.
- Установите в поле cdr новой ячейки cons прежнее (и все еще текущее) значение
a
(т.е. скопируйте содержимое ячейки переменной a
).
- Установите переменную ячейку
a
в новую ячейку cons.
После этого вызова соответствующие структуры данных выглядят так:
symbol cons cons cons
+-------+----------+ +------+--|---+ +------+------+ +------+------+
|name: |variable: | |car: |cdr: | |car: |cdr: | |car: |cdr: |
| a | | | | 3 | | | | 1 | | | | 2 | nil |
+-------+----|-----+ +------+--|---+ +------+--|---+ +------+------+
| ↑ | ↑ | ↑
+-------------+ +-------+ +-------+
Вызов setcar
не создает никакой новой структуры данных и не воздействует на символ a
, но на его значение, которое является ячейкой cons, в которой car
в настоящее время содержит 3. После (setcar a 4)
, структуры данных выглядят так:
symbol cons cons cons
+-------+----------+ +------+--|---+ +------+------+ +------+------+
|name: |variable: | |car: |cdr: | |car: |cdr: | |car: |cdr: |
| a | | | | 4 | | | | 1 | | | | 2 | nil |
+-------+----|-----+ +------+--|---+ +------+--|---+ +------+------+
| ↑ | ↑ | ↑
+-------------+ +-------+ +-------+
push
- макрос; здесь (push 5 a)
эквивалентно (set 'a (cons 5 a))
.
setq
и push
- макросы (setq
- это «специальная форма», что, как мы здесь говорим, означает макрос, определение которого встроено в интерпретатор и не предоставлено в Лиспе). Макросы получают свои аргументы без оценки и могут расширить их или нет. set
, setcar
и add-to-list
- это функции, которые получают свои аргументы оцененными. Оценка символа возвращает содержимое его переменной ячейки, например, после начального (setq a '(1 2))
значение символа a
- это ячейка cons, в которой содержится 1
.
Если вы все еще в замешательстве, я предлагаю поэкспериментировать с (setq b a)
и посмотреть, какие выражения меняют b
, когда вы действуете на a
(те, которые действуют на символ a
), а какие не (те, которые влияют на значение символа a
).