В чем разница между 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) не будет делать то же самое).

Другие вопросы по тегам