Какая разница между 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]>
То, что я нашел, абсолютно то же самое.
Я не могу понять, что с ними другое?
Ответы
Ответ 1
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
Ответ 2
Оба defvar
и defparameter
объявят переменную как "динамически измененную переменную". Кроме того, defparameter
всегда будет устанавливать значение переменной в значение, которое вы передаете в качестве второго аргумента. Это отличается от defvar
, оно установит только значение переменной, если оно ранее не было установлено.
Определение переменной с setf
или setq
в глобальной лексической области undefined. Некоторые реализации создадут для вас динамически скопированную переменную, некоторые - нет. Вы можете видеть диагностические сообщения, когда вы делаете это в первый раз.
Чтобы понять разницу между переменными с лексическим и динамическим диапазоном, попробуйте следующий фрагмент кода:
* (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)
не будет делать то же самое).