В чем разница между defvar, defparameter, setf и setq
Я нашел похожий вопрос.
Но я не совсем понимаю это объяснение.
Поэтому я пытаюсь запустить clisp со следующим примером:
[1]> (defvar a 5)
A
[2]> (+ a 1)
6
[3]> (defparameter b 5)
B
[4]> (+ b 1)
6
[5]> (setf c 5)
5
[6]> (+ c 1)
6
[7]> (setq d 5)
5
[8]> (+ d 1)
6
[9]> (let ((a 500)) (+ a 1))
501
[10]> (let ((b 500)) (+ b 1))
501
[11]> (let ((c 500)) (+ c 1))
501
[12]> (let ((d 500)) (+ d 1))
501
[13]>
То, что я нашел, совершенно то же самое.
Я не могу понять, что с ними не так?
2 ответа
DEFPARAMETER всегда присваивает значение. Так:
[1]> (defparameter a 1)
A
[2]> (defparameter a 2)
A
[3]> a
2
в то время как DEFVAR делает это только один раз, поэтому:
[4]> (defvar b 1)
B
[5]> (defvar b 2)
B
[6]> b
1
SETF - это макрос, который использует SETQ для внутреннего использования, но имеет больше возможностей. В каком-то смысле это более общий оператор присваивания. Например, с помощью SETF вы можете сделать:
[19]> (defparameter c (list 1 2 3))
[21]> (setf (car c) 42)
42
[22]> c
(42 2 3)
но вы не можете сделать это с помощью SETQ:
[23]> (setq (car c) 42)
*** - SETQ: (CAR C) is not a symbol
The following restarts are available:
USE-VALUE :R1 Input a value to be used instead.
ABORT :R2 Abort main loop
Break 1 [24]> abort
И то и другое defvar
а также defparameter
объявит переменную как "переменную с динамической областью действия". К тому же, defparameter
всегда будет устанавливать значение переменной равным значению, которое вы передаете в качестве второго аргумента. Это отличается от defvar
, он будет устанавливать значение переменной, только если оно ранее не было установлено.
Определение переменной с setf
или же setq
в глобальном лексическом масштабе не определено. Некоторые реализации создадут переменную с динамической областью действия для вас, некоторые - нет. Вы можете увидеть диагностические сообщения, когда вы делаете это в первый раз.
Чтобы понять разницу между переменными в лексической и динамической областях, попробуйте следующий фрагмент кода:
* (defvar *a* 1)
*A*
* (let ((*a* 5)) (defun demo-a () *a*))
DEMO-A
* (let ((b 5)) (defun demo-b () b))
DEMO-B
* (let ((*a* 100)) (demo-a))
100
* (let ((b 100)) (demo-b))
5
Здесь мы создаем переменную с динамической областью действия и функцию, которая возвращает значение (определенное внутри привязки, где оно имеет другое значение при создании функции, в этом нет необходимости, и это делается только для того, чтобы выглядеть похожим на лексическое замыкание над b). Затем мы определяем новую переменную и определяем функцию, возвращающую ее значение.
После этого мы вызываем обе функции внутри замыканий, привязывая значение к переменной с тем же именем. В случае динамического определения объема это та же самая переменная. В случае лексического замыкания (b) они просто имеют одно и то же имя, но не являются одной и той же переменной, поскольку они определены в двух разных лексических замыканиях.
Насколько разница между setf
а также setq
попробуйте всегда использовать setf
(Я не могу вспомнить ни одного примера, где (setq blah blahblah)
будет работать и (setf blah blahblah)
не будет делать то же самое).