Je m'apprends un peu plus et j'ai rencontré le problème suivant:
Si je veux réinitialiser une variable de liste, elle ne sera pas mise à jour après la première évaluation. Voici un exemple de code:
(defun initilize ()
(setq example '(3)))
(defun modify ()
(initilize)
(message "%S" example)
(setcar example 2))
; M-x eval-buffer RET
(modify) ; message --> (3)
(modify) ; message --> (2)
(modify) ; message --> (2)
Je m'intéresse à deux choses. La première consiste à en savoir plus sur ce qui se passe "sous le capot", alors pourquoi cela fonctionne-t-il la première fois et échoue lors des appels suivants?
La deuxième question, plus pratique, est de savoir comment réinitialiser correctement la liste ou existe-t-il une autre façon courante de faire quelque chose comme ça?
Une solution de contournement que je me suis trouvée consiste à utiliser une liste citée et à évaluer le contenu comme ceci:
(setq example `(,3))
list
quote
mutability
clemera
la source
la source
'(some list)
à êtreeq
à'(some list)
- jamais .Il est généralement aucune garantie dans ce code Lisp qui cite visiblement un rendement de liste nouvelle structure de la liste à chaque fois. Dans certaines implémentations Lisp, cela peut ou peut parfois arriver. Dans d'autres, ce n'est jamais le cas. Votre code ne devrait de toute façon pas dépendre d'un tel comportement de l'implémentation. Si vous voulez une nouvelle structure de liste, utilisezlist
oucons
ou équivalent.example
n'a jamais été déclaré en tant que variable, ilsetq
doit donc agir comme s'il déclarait une nouvelle variable, mais plus tard, lorsque vous appelez àinitialize
nouveau, une nouvelle variable est en cours de création, tout en semodify
souvenant de l'ancienne ... dans tous les cas, ce n'est pas un comportement attendu, cependant, l'utilisation desetq
avec quelque chose qui n'a pas été introduit plus tôt comme variable pourrait tout aussi bien être indéfinie.'(3)
est traité comme une valeur littérale, donc une fois que vous(setcar '(3) 2)
, quand vous le ferez(defvar foo '(3))
ou(let ((foo '(3)))
ainsi de suite, vous obtiendrez probablement une valeurfoo
égale à'(2)
. Je dis "probable" parce que ce comportement n'est pas garanti, c'est une sorte d'optimisation que l'interprète fait chaque fois qu'il le souhaite, quelque chose appelé élimination de la sous-expression des constantes (un cas particulier de). Donc, ce qu'abo-abo a écrit n'est pas exactement la raison. Cela ressemble plus à la modification d'un littéral de chaîne en C (ce qui génère généralement un avertissement).Réponses:
Peut-être que cela dissipera une partie de la confusion:
Votre fonction
initilize
n'initialise pas la variableexample
. Il le définit sur une cellule de contre particulière - la même cellule de contre chaque fois qu'il est appelé. La première fois que l'initilize
on appelle, l'setq
assigneexample
à une nouvelle cellule contre, qui est le résultat de l'évaluation'(3)
. Appels ultérieurs pourinitilize
simplement réaffecterexample
à la même cellule de contre.Comme il
initilize
suffit de réaffecter la même cellule de contre àexample
, ilmodify
suffit de définir la voiture de cette même cellule de contre à2
chaque appel.Pour initialiser une liste, utilisez
list
oucons
(ou un sexp équivalent de backquote, tel que`(,(+ 2 1))
ou`(,3)
). Par exemple, utilisez(list 3)
.La clé pour comprendre cela est de savoir qu'une cellule contre citée n'est évaluée qu'une seule fois, puis la même cellule contre est retournée. Ce n'est pas nécessairement la façon dont tous les Lisps se comportent, mais c'est la façon dont Emacs Lisp se comporte.
Plus généralement, le comportement de l'évaluation d'un objet mutable cité dépend de l'implémentation, sinon de la langue. En Common Lisp, par exemple, je suis quasiment sûr qu'il n'y a rien dans la définition (spec) du langage qui définit le comportement à cet égard - c'est laissé à l'implémentation.
Résumé: Ne vous attendez pas à ce que '(une liste) soit égal à' (une liste) - jamais. Il n'y a généralement aucune garantie dans Lisp que le code qui cite visiblement une liste renvoie à chaque fois une nouvelle structure de liste. Dans certaines implémentations Lisp, cela peut ou peut parfois arriver. Dans d'autres, ce n'est jamais le cas. Votre code ne devrait de toute façon pas dépendre d'un tel comportement de l'implémentation. Si vous voulez une nouvelle structure de liste, utilisez
list
oucons
ou équivalent.la source
Vous pouvez utiliser
(setq example (list 3))
pour éviter cette erreur.Ce qui se passe, c'est
init
attribue un objet qui contient initialement(3)
àexample
. Il définit la valeur de l'objet une seule fois. Par la suite, vous modifiez cette valeur.Voici votre exemple en C ++, si vous le comprenez mieux:
la source
initilize
fonction et que j'appelle àmodify
nouveau, elle ne réapparaîtra(3)
que parce que j'ai réévalué la fonction.(3)
à un objet temporaire qui en fait partieinit
.init
Le corps de 's définitexample
à l'adresse de cet objet temporaire, il ne touche pas sa valeur.