Lier plusieurs valeurs directement à partir de la liste sans lier la liste elle-même

12

Est-il possible d'affecter plusieurs valeurs de retour directement aux variables sans passer par une variable temporaire dans Emacs Lisp?

Par exemple, supposons que j'ai une fonction qui renvoie une liste de deux listes:

(defun test-func ()
  (setq a '(a b))
  (setq b '(c d))
  `(,a ,b))

Si je veux affecter la première valeur de retour à list-aet la deuxième valeur de retour à list-b, je peux le faire en utilisant une variable temporaire temp, par exemple:

(let* ((temp (test-func)) (list-a (car temp)) (list-b (cadr temp)))
  (message-box (prin1-to-string list-a))
  (message-box (prin1-to-string list-b)))

Est-il possible de faire cela plus simplement? (Je suis habitué à Perl et Python où vous n'avez pas besoin de spécifier une variable temporaire)

Håkon Hægland
la source
2
Vous pouvez essayer la cl-destructuring-bindmacro. Aussi, aviez-vous vraiment l'intention d'utiliser à l' setqintérieur d'un defun? setqcrée une variable "spéciale" (accessible globalement), quelque chose que vous mettriez généralement en dehors d'une fonction (car il n'y a pas de sens à déclarer la même variable plus d'une fois, alors que les fonctions sont destinées à être exécutées plusieurs fois).
wvxvw
@wvxvw Merci! Oui, j'ai oublié d'utiliser l' letintérieur de la fonction .. Je n'avais pas prévu de définir de variables globales :)
Håkon Hægland

Réponses:

8

Common Lisp a une fonction spéciale - plusieurs valeurs , et la bibliothèque de compatibilité Emacs Lisp les émule à l'aide de listes .

Ainsi vous pouvez faire

(defun test-fun ()
  (let ((a 1) (b 2))
    (cl-values a b)))

(cl-multiple-value-bind (a b) (test-fun)
  ...)

(chargez cl-libet utilisez le cl-préfixe pour toutes les fonctionnalités CL dans EL).

NB : si vous regardez la réponse SO liée ci-dessus, vous verrez que l'émulation de MV avec des listes est, pour le dire légèrement, sous-optimale (voir aussi le commentaire de @ Stefan ci-dessous).

sds
la source
Y a-t-il un avantage à utiliser multiple-value-bindau lieu de cl-multiple-value-bind(seul ce dernier semble être documenté dans le manuel gnu.org/software/emacs/manual/html_node/cl/Multiple-Values.html )?
Håkon Hægland
3
@ HåkonHægland Ils ont la même fonction, mais vous devez utiliser cette dernière . Le clpackage n'est plus destiné à être utilisé. Vous devriez toujours utiliser le cl-libpackage à la place, qui définit les fonctions avec le cl-préfixe ..
Malabarba
1
Je déconseille l'utilisation de cl-values: c'est une émulation de "meilleur effort" de CommonLisp valuesmais ce n'est pas vraiment compatible car il ne fait que renvoyer une liste (c'est à dire que c'est un mensonge), et d'après mon expérience, les gens se retrouvent tôt ou tard les manipuler comme des listes (c'est-à-dire rompre l'abstraction): mieux utiliser les listes explicitement (et si vous n'aimez pas pcase-let, alors utilisez cl-destructuring-bindplutôt que cl-multiple-value-bind).
Stefan
4

En plus de compter sur le cl-libpackage de compatibilité, la manière recommandée dans Elisp pour cela est d'utiliser pcase:

(defun test-fun
  (let ((a '(a b))
        (b '(c d)))
    `(,a ,b)))

(defun other-test-fun ()
  (pcase-let ((`(,a ,b) (test-fun)))
    (message "a = %s; b = %s" a b)))

A côté pcase-let, il y a aussi pcase-dolist, pcase-lambdaet pcaselui - même.

Stefan
la source