Ответ 1
Здесь представлена диаграмма, представляющая символ 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 отсутствует в списке. Это выражение делает четыре вещи:
- Создайте новую ячейку cons.
- Установите новое поле ячейки ячейки cons на
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
является "специальной формой", что, насколько нам известно, означает макрос, определение которого встроено в интерпретатор и не представлено в Lisp), Макросы получают неопровержимые аргументы и могут выбрать их расширение или нет. set
, setcar
и add-to-list
- это функции, которые получают свои аргументы. Оценка символа возвращает содержимое его слота переменной, например. после начального (setq a '(1 2))
значение символа a
является ячейкой cons, чей автомобиль содержит 1
.
Если вы все еще сбиты с толку, я предлагаю экспериментировать с (setq b a)
и видеть для себя, какое из выражений изменить b
, когда вы действуете на a
(те, которые действуют на символ a
) и которые (те, которые действуют на значение символа a
).