7
votes

En commun-LISP, comment modifier une partie d'un paramètre de liste à partir d'une fonction sans changer la liste d'origine?

J'essaie de transmettre une liste à une fonction de LISP et de modifier le contenu de cette liste dans la fonction sans affecter la liste d'origine. J'ai lu que Lisp est une valeur réussie, et c'est vrai, mais il y a autre chose que je ne comprends pas tout à fait. Par exemple, ce code fonctionne comme prévu: xxx

si vous appelez (test), il imprime (a b c) même si (modifier) ​​renvoie (x y z).

Cependant, cela ne fonctionne pas de cette façon si vous essayez de changer juste une partie de la liste. Je suppose que cela a quelque chose à voir avec les listes qui ont le même contenu étant la même en mémoire partout ou quelque chose comme ça? Voici un exemple: xxx

puis (test) impression (x b c). Alors, comment modifier certains éléments d'un paramètre de liste dans une fonction, comme si cette liste était locale à cette fonction?


2 commentaires

Notez que les conséquences de la modification des constantes littérales sont indéfinies. Ne fais pas ça. Jamais. '(A b c) est une constante littérale dans votre code. Vous ne devriez pas le modifier. Vous pouvez modifier des listes créées avec la liste de fonctions comme (liste 'A' B 'C).


Notez également que (Setf Original '(A B C)) n'a aucun sens. Setf n'introduit pas de variables. La variable «originale» n'est nulle partement définie. Vous pouvez définir des variables introduites via Let, Defun, Defvar, Defparamètre, ...


4 Réponses :


2
votes

Vous avez probablement des problèmes car même si la LISP est transmise des références à valeur à des objets, comme dans Java ou Python. Vos cellules de la client contiennent des références que vous modifiez, de sorte que vous modifiez à la fois l'original et la section locale.

imo, vous devriez essayer d'écrire des fonctions dans un style plus fonctionnel pour éviter de tels problèmes. Même si la LISP commune est multi-paradigme, un style fonctionnel est un moyen plus approprié.

(défunement modifier (n) (CONS 'X (CDR N))


2 commentaires

Ceci est mon premier projet dans Lisp et je ne comprends pas vraiment la programmation fonctionnelle. Je suppose que j'ai juste besoin de repenser la façon dont j'ai structuré mon programme? J'essaie d'examiner les modifications potentielles à un état de jeu sans modifier l'état. Donc, au lieu de faire des fonctions pour Makechanger et Indochange, j'espérais que je puisse simplement modifier une "copie" de l'État.


Généralement, il est sage d'éviter des changements d'état inutiles. Souvent, vous n'en avez pas besoin d'eux et ils vous font que vous programmez plus fort de déboguer et de conduire à des erreurs telles que celles-ci.



7
votes

SETF modifie un endroit . n peut être un endroit. Le premier élément de la liste n peut également être un lieu.

Dans les deux cas, la liste détenue par Original est transmise à Modifier comme paramètre n . Cela signifie que les deux original dans la fonction test et n dans la fonction modifient détiennent maintenant la même liste, qui signifie que les deux original et n pointent maintenant à son premier élément.

Après que SETF modifie n dans le premier cas, il ne pointe plus de cette liste mais dans une nouvelle liste. La liste pointée par original n'est pas affectée. La nouvelle liste est ensuite renvoyée par Modifier , mais puisque cette valeur n'est attribuée à rien, il s'estompe hors de l'existence et sera bientôt recueilli.

Dans le second cas, SETF modifie non n , mais le premier élément de la liste n points à. Ceci est la même liste original points à, donc, ensuite, vous pouvez voir la liste modifiée également via cette variable.

Pour copier une liste, utilisez .


0 commentaires

14
votes

Les listes LISP sont basées sur les cellules de contre. Les variables sont comme des pointeurs sur des cellules de consacre (ou d'autres objets LISP). Changer une variable ne changera pas d'autres variables. La modification des cellules de la consommation sera visible dans tous les endroits où il y a des références à ces cellules de contre.

Un bon livre est Touretzky, Common Lisp: une introduction douce au calcul symbolique . P>

Il existe également un logiciel qui dessine des arbres de listes et des cellules de contre. p>

Si vous passez une liste à une fonction comme celle-ci: p> xxx pré>

Ensuite, vous avez trois manières différentes d'utiliser la liste: p>

Modification destructrice des cellules de contre forts> p> xxx pré>

Station de structure forte> p> xxx pré>

ci-dessus renvoie une liste qui partage la structure avec la liste transmise: les éléments de repos sont les mêmes dans les deux listes. P> Copie forte> P>

(defun foo (original-list)
   (setf (first original-list) 'bar))


1 commentaires

Merci. C'était très serviable pour moi.



5
votes

C'est presque le même que cet exemple en C:

void modify1(char *p) {
    p = "hi";
}

void modify2(char *p) {
    p[0] = 'h';
}


1 commentaires

J'aurais aimé qu'il y ait un livre qui explique les opérations équivalentes, chaque fois que cela est possible, en ce qui concerne C. A C Programmer concernera certains aspects du LISP commun beaucoup plus rapidement.