web-dev-qa-db-fra.com

Quelle est la différence entre defvar, defparameter, setf et setq

J'ai trouvé un question similaire .

Mais je ne comprends pas très bien cette explication.

J'essaie donc d'exécuter clisp avec l'exemple suivant:

  [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]> 

Ce que j'ai trouvé est totalement le même.

Je ne peux pas comprendre ce qui est différent avec eux?

41
sam

DEFPARAMETER attribue toujours une valeur. Alors:

[1]> (defparameter a 1)
A
[2]> (defparameter a 2)
A
[3]> a
2

alors que DEFVAR ne le fait qu'une seule fois, donc:

[4]> (defvar b 1)
B
[5]> (defvar b 2)
B
[6]> b
1

SETF est une macro qui utilise SETQ en interne, mais a plus de possibilités. D'une certaine manière, c'est un opérateur d'affectation plus général. Par exemple. avec SETF vous pouvez faire:

[19]> (defparameter c (list 1 2 3))
[21]> (setf (car c) 42)                                              
42
[22]> c
(42 2 3)

mais vous ne pouvez pas faire cela avec 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
65
Michał Kwiatkowski

defvar et defparameter déclareront une variable comme une "variable à portée dynamique". De plus, defparameter définira toujours la valeur de la variable sur la valeur que vous transmettez comme deuxième argument. Ceci est différent de defvar, il ne définira la valeur de la variable que si elle n'a pas été définie auparavant.

La définition d'une variable avec setf ou setq dans la portée lexicale globale n'est pas définie. Certaines implémentations créeront pour vous une variable de portée dynamique, d'autres non. Vous pouvez voir des messages de diagnostic lorsque vous le faites pour la première fois.

Pour comprendre la différence entre les variables à portée lexicale et à portée dynamique, essayez l'extrait de code suivant:

* (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

Ici, nous créons une variable à portée dynamique et une fonction qui renvoie la valeur (définie dans une liaison où elle a une valeur différente lors de la création de la fonction, cela n'est pas nécessaire et fait uniquement pour ressembler à la fermeture lexicale sur b). Nous définissons ensuite une nouvelle variable et définissons une fonction qui renvoie sa valeur.

Après cela, nous appelons les deux fonctions, à l'intérieur des fermetures liant une valeur à une variable du même nom. Dans le cas de la portée dynamique, il s'agit de la même variable. Dans le cas de fermeture lexicale (b), ils ont simplement le même nom, mais ne sont pas la même variable, car ils sont définis dans deux fermetures lexicales différentes.

En ce qui concerne la différence entre setf et setq, essayez de toujours utiliser setf (je ne vois aucun exemple où (setq blah blahblah) fonctionnerait et (setf blah blahblah) ne ferait pas la même chose).

25
Vatine