Powiąż wiele wartości bezpośrednio z listy bez wiązania samej listy

12

Czy możliwe jest przypisanie wielu zwracanych wartości bezpośrednio do zmiennych bez przechodzenia przez zmienną tymczasową w Emacs Lisp?

Załóżmy na przykład, że mam funkcję, która zwraca listę dwóch list:

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

Jeśli chcę przypisać pierwszą wartość zwracaną list-ai drugą wartość zwracaną list-b, mogę to zrobić za pomocą zmiennej tymczasowej temp, na przykład:

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

Czy można to zrobić prościej? (Jestem przyzwyczajony do Perla i Pythona, gdzie nie musisz określać zmiennej tymczasowej)

Håkon Hægland
źródło
2
Możesz spróbować cl-destructuring-bindmakro. Ponadto, czy naprawdę zamierzałeś używać w setqśrodku defun? setqtworzy „specjalną” (globalnie dostępną) zmienną, coś, co zwykle umieszcza się poza funkcją (ponieważ deklarowanie tej samej zmiennej więcej niż raz ma niewiele sensu, podczas gdy funkcje mają być uruchamiane więcej niż jeden raz).
wvxvw
@wvxvw Dzięki! Tak, zapomniałem użyć letwewnątrz funkcji. Nie planowałem ustawiać żadnych zmiennych globalnych :)
Håkon Hægland

Odpowiedzi:

8

Common Lisp ma specjalną funkcję - wiele wartości , a biblioteka kompatybilności Emacs Lisp emuluje je za pomocą list .

W ten sposób możesz zrobić

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

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

(załaduj cl-libi użyj cl-prefiksu dla wszystkich funkcji CL w EL).

Uwaga : jeśli spojrzysz na odpowiedź SO podaną powyżej, zobaczysz, że emulacja MV za pomocą list jest, delikatnie mówiąc, suboptymalna (patrz również komentarz @ Stefana poniżej).

sds
źródło
Czy jest jakaś korzyść z używania multiple-value-bindzamiast cl-multiple-value-bind(tylko to drugie wydaje się udokumentowane w podręczniku gnu.org/software/emacs/manual/html_node/cl/Multiple-Values.html )?
Håkon Hægland
3
@ HåkonHægland one taką samą funkcję, ale należy używać ostatni . clPakiet nie ma być już używane. Zamiast tego zawsze powinieneś używać cl-libpakietu, który definiuje funkcje z cl-prefiksem ..
Malabarba
1
cl-valuesOdradzam stosowanie : jest to emulacja „Common wysiłku” CommonLisp, valuesale nie jest tak naprawdę zgodna, ponieważ wszystko, co robi, to zwrócenie listy (tj. Rodzaj kłamstwa), a według mojego doświadczenia ludzie prędzej czy później skończą manipulowanie nimi jako listami (tj. łamanie abstrakcji): lepiej używaj list jawnie (a jeśli ci się nie podoba pcase-let, użyj cl-destructuring-bindraczej niż cl-multiple-value-bind).
Stefan
4

Oprócz polegania na cl-libpakiecie kompatybilności, zalecanym sposobem w Elisp jest użycie 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)))

Obok pcase-let, tam także pcase-dolist, pcase-lambdai pcasesama.

Stefan
źródło