Vincula varios valores directamente desde la lista sin vincular la lista misma

12

¿Es posible asignar múltiples valores de retorno directamente a las variables sin pasar por una variable temporal en Emacs Lisp?

Por ejemplo, supongamos que tengo una función que devuelve una lista de dos listas:

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

Si quiero asignar el primer valor de retorno a list-ay el segundo valor de retorno a list-b, puedo hacer esto usando una variable temporal temp, por ejemplo:

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

¿Es posible hacer esto de manera más simple? (Estoy acostumbrado a Perl y Python donde no tienes que especificar una variable temporal)

Håkon Hægland
fuente
2
Puedes probar cl-destructuring-bindmacro. Además, ¿realmente pretendías usar setqdentro de a defun? setqcrea una variable "especial" (accesible a nivel mundial), algo que normalmente pondría fuera de una función (porque tiene poco significado declarar la misma variable más de una vez, mientras que las funciones deben ejecutarse más de una vez).
wvxvw
@wvxvw Gracias! Sí, olvidé usar letdentro de la función. No tenía planeado establecer ninguna variable global :)
Håkon Hægland

Respuestas:

8

Common Lisp tiene una instalación especial: múltiples valores , y la biblioteca de compatibilidad Emacs Lisp los emula usando listas .

Así puedes hacer

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

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

(Cargue cl-liby use el cl-prefijo para toda la funcionalidad CL en EL).

NB : si mira la respuesta SO vinculada anteriormente, verá que emular MV con listas es, por decirlo suavemente, subóptimo (vea también el comentario de @ Stefan a continuación).

sds
fuente
¿Hay alguna ventaja de usar en multiple-value-bindlugar de cl-multiple-value-bind(solo este último parece estar documentado en el manual gnu.org/software/emacs/manual/html_node/cl/Multiple-Values.html )?
Håkon Hægland
3
@ HåkonHægland Son la misma función, pero debe usar la última . El clpaquete ya no está destinado a ser utilizado. Siempre debe usar el cl-libpaquete, que define las funciones con el cl-prefijo ..
Malabarba
1
Recomiendo contra el uso de cl-values: es una emulación de "mejor esfuerzo" de CommonLisp, valuespero no es realmente compatible, ya que todo lo que hace es devolver una lista (es decir, es una mentira), y en mi experiencia la gente tarde o temprano termina manipulando esos como listas (es decir, rompiendo la abstracción): mejor use las listas explícitamente (y si no le gusta pcase-let, entonces use en cl-destructuring-bindlugar de cl-multiple-value-bind).
Stefan
4

Además de confiar en el cl-libpaquete de compatibilidad, la forma recomendada en Elisp es usar 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)))

Al lado pcase-let, también hay pcase-dolist, pcase-lambday pcaseen sí.

Stefan
fuente