Vincular vários valores diretamente da lista sem vincular a própria lista

12

É possível atribuir vários valores de retorno diretamente às variáveis ​​sem passar por uma variável temporária no Emacs Lisp?

Por exemplo, digamos que eu tenho uma função que retorna uma lista de duas listas:

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

Se eu quiser atribuir o primeiro valor de retorno list-ae o segundo valor de retorno list-b, posso fazer isso usando uma variável temporária temp, por exemplo:

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

É possível fazer isso de maneira mais simples? (Estou acostumado a Perl e Python, onde você não precisa especificar uma variável temporária)

Håkon Hægland
fonte
2
Você pode tentar cl-destructuring-bindmacro. Além disso, você realmente pretendia usar setqdentro de um defun? setqcria uma variável "especial" (acessível globalmente), algo que você normalmente colocaria fora de uma função (porque há pouco significado em declarar a mesma variável mais de uma vez, enquanto as funções devem ser executadas mais de uma vez).
wvxvw
@wvxvw Thanks! Sim, eu esqueci de usar letdentro da função .. Eu não planejei para definir quaisquer variáveis globais :)
Håkon Hægland

Respostas:

8

O Common Lisp possui uma instalação especial - vários valores , e a biblioteca de compatibilidade do Emacs Lisp os emula usando listas .

Assim você pode fazer

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

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

(carregue cl-libe use o cl-prefixo para toda a funcionalidade CL no EL).

Nota : se você olhar para a resposta do SO vinculada acima, verá que emular MV com listas é, para dizer o mínimo, subótimo (consulte também o comentário de @ Stefan abaixo).

sds
fonte
Existe alguma vantagem em usar em multiple-value-bindvez de cl-multiple-value-bind(apenas o último parece estar documentado no manual gnu.org/software/emacs/manual/html_node/cl/Multiple-Values.html )?
Håkon Hægland 26/01
3
@ HåkonHægland Eles têm a mesma função, mas você deve usar a última . O clpacote não deve ser usado mais. Você deve sempre usar o cl-libpacote em vez disso, que define funções com o cl-prefixo ..
Malabarba
1
Eu recomendaria contra o uso de cl-values: é uma emulação de "melhor esforço" do CommonLisp, valuesmas não é realmente compatível, pois tudo o que faz é retornar uma lista (isto é, é uma mentira) e, na minha experiência, as pessoas mais cedo ou mais tarde acabam manipulando-os como listas (ou seja, quebrando a abstração): use melhor as listas explicitamente (e se você não gostar pcase-let, use em cl-destructuring-bindvez de cl-multiple-value-bind).
Stefan
4

Além de contar com o cl-libpacote de compatibilidade, a maneira recomendada no Elisp para isso é 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)))

Ao lado pcase-let, há também pcase-dolist, pcase-lambdae pcaseem si.

Stefan
fonte