Comment évaluer les variables avant de les ajouter à une liste?

30

Ce qui suit ne fonctionne évidemment pas et d'où cette question.

Comment puis-je corriger le code ci-dessous pour que la valeur de somelistdevienne '(("abc" . 123))?

(setq x "abc")
(setq y 123)
(setq somelist nil)
(add-to-list 'somelist '(x . y))
Kaushal Modi
la source
5
Avez-vous essayé de quasiquoter? Essayez `(,x . ,y).
Dan
Ah, c'est ce que j'ai raté. Je ne savais pas pour quoi google :). J'ai essayé (add-to-list 'somelist '(,x . ,y))mais j'ai oublié la citation.
Kaushal Modi
Les questions considérées comme des doublons de celui-ci reviennent très souvent. Quelqu'un peut-il trouver un moyen de faire comprendre aux débutants que cette question / réponse est ce qu'ils recherchent? Je soupçonne qu'une partie du problème est que le titre de cette question n'a de sens que si vous connaissez déjà la cause profonde du problème (c'est-à-dire que vous connaissez en quelque sorte la réponse). J'essaie de m'imaginer comme un utilisateur qui n'a aucune idée que les variables doivent être évaluées et encore moins une idée de ce que signifie le "devis", mais je viens à vide. @A dessiné?
Stefan
@stefan: Contrairement au cas où il y a un message d'erreur (qui peut être utilisé dans le titre de la question d'une communauté Q + A), l'erreur, le cas échéant, résultant de la citation de quelque chose qui doit être évalué (et ceci est un particulier cas de cela) peut être bien loin du site du devis. Plus communément, il n'y a pas d'erreur (Emacs) - juste un comportement qui ne correspond pas à ce que l'utilisateur voulait.
Drew
@Stefan: Aucun grand titre de question ne me vient à l'esprit. Mais nous pourrions au moins formuler une question qui y répond directement, y compris peut-être un cas "normal" qui appelle simplement à supprimer un guillemet et un cas qui appelle à la mise en quasiquotation. Un bon Q, couvrant de tels cas, et une bonne réponse les couvrant, seraient utiles. Mais en ce qui concerne la recherche de Q qui sont des doublons: sans message d'erreur dans le titre Q, il faut lire toute la question et savoir comment trouver le doublon vers lequel pointer.
Drew

Réponses:

30

La question générale est que vous avez besoin xet yà évaluer avant qu'ils ne soient insérés dans somelist. Le problème avec la liste citée (avec 'comme syntaxe de lecteur) est qu'il quotes'agit d'un formulaire spécial qui n'évalue pas son argument. Selon le docstring:

(quote ARG)

Renvoie l'argument, sans l'évaluer. (quote x)rendements x. Attention: quotene construit pas sa valeur de retour, mais renvoie simplement la valeur qui a été pré-construite par le lecteur Lisp ...

Par conséquent, vous devez soit ajouter des guillemets, soit utiliser une fonction qui évalue les arguments.

Le backquoting vous permet d'évaluer sélectivement les éléments d'une liste backquoted avec la ,syntaxe:

(setq x "x-val" y "y-val" z "z-val" somelist nil)
'(x  y z)                            ; => (x y z)
`(x ,y z)                            ; => (x "y-val" z)
(add-to-list 'somelist `(x y ,z))    ; => ((x y "z-val"))

Alternativement, vous pouvez utiliser cons(comme @tarsius suggère dans sa réponse) ou, pour un nombre arbitraire d'éléments, list:

(add-to-list 'somelist (cons x y))   ; => (("x-val" . "y-val"))
(setq somelist nil)                  ; reset
(add-to-list 'somelist (list x y z)) ; => (("x-val" "y-val" "z-val"))

Le choix dépend de ce que vous devez faire avec les éléments.

Dan
la source
19

Ne citez pas la cellule contre, car les expressions entre guillemets ne sont pas évaluées. C'est exactement pourquoi on cite - pour empêcher l'évaluation. Mais ce n'est pas ce que vous voulez, alors ne le faites pas.

Utilisez plutôt le formulaire qui crée une cellule contre à partir de deux valeurs évaluées, ses arguments.

(cons x y)

Bien sûr, vous pouvez également quasiquote mais cela n'a pas vraiment de sens ici, et semble pire. Utilisez uniquement `et ,lorsque cela améliore la lisibilité, c'est-à-dire lorsque vous faites quelque chose de plus complexe que de construire une contre-cellule ou d'ajouter un atome ou une liste au début d'une liste existante.

En utilisant des quasiquotes, cela ressemblerait à ceci:

`(,x . ,y)

Ce qui est pire car il utilise une syntaxe supplémentaire qui n'est pas du tout requise dans ce cas et obscurcit celle qui consest utilisée.

tarse
la source
3
Bon point sur consing. Les quasiquotes me semblent concerner davantage le contrôle fin du contenu de la liste que la lisibilité, mais je conviens que le cas d'utilisation est logique cons.
Dan
Merci pour votre réponse. Ce fut un grand moment TIL pour moi. Je mettais aveuglément des citations avant les listes et les inconvénients.
Kaushal Modi
@Dan, eh bien oui - et non. Quasiquoting ne peut rien faire que vous ne pouviez pas faire avec juste cons, listet nconc. Sauf que c'est plus joli. C'est du sucre syntaxique qui est utile lorsque vous avez besoin d'un "contrôle fin du contenu de la liste" (comme dans "faire quelque chose de plus complexe que d'ajouter un atome ou une liste au début"). Et l'avantage supplémentaire d'utiliser ce sucre syntaxique est: la lisibilité. Le quasiquoting ne vous donne pas un contrôle supplémentaire plus fin - il vous permet simplement de faire la même chose avec moins de bogues lors de la tentative initiale. :-)
tarsius