Привязка нескольких значений напрямую из списка без привязки самого списка

12

Можно ли назначить несколько возвращаемых значений непосредственно переменным, не проходя временную переменную в Emacs Lisp?

Например, допустим, у меня есть функция, которая возвращает список из двух списков:

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

Если я хочу назначить первое возвращаемое значение list-aи второе возвращаемое значение list-b, я могу сделать это с помощью временной переменной temp, например:

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

Можно ли сделать это проще? (Я привык к Perl и Python, где вам не нужно указывать временную переменную)

Хокон Хагланд
источник
2
Вы можете попробовать cl-destructuring-bindмакрос. Кроме того, вы действительно намеревались использовать setqвнутри defun? setqсоздает «специальную» (глобально доступную) переменную, которую вы обычно помещаете вне функции (поскольку нет смысла объявлять одну и ту же переменную более одного раза, в то время как функции предназначены для запуска более одного раза).
wvxvw
@wvxvw Спасибо! Да, я забыл использовать letвнутри функции .. Я не планировал устанавливать какие-либо глобальные переменные :)
Håkon Hægland

Ответы:

8

Common Lisp имеет специальное средство - множественные значения , и библиотека совместимости Emacs Lisp эмулирует их, используя списки .

Таким образом, вы можете сделать

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

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

(загрузить cl-libи использовать cl-префикс для всех функций CL в EL).

NB : если вы посмотрите на ответ SO, связанный выше, вы увидите, что эмуляция MV со списками, мягко говоря, неоптимальна (см. Также комментарий @ Stefan ниже).

ДСН
источник
Есть ли какое-либо преимущество использования multiple-value-bindвместо cl-multiple-value-bind(кажется, что только последнее описано в руководстве gnu.org/software/emacs/manual/html_node/cl/Multiple-Values.html )?
Хокон Хагланд
3
@ HåkonHægland Это одна и та же функция, но вы должны использовать последнюю . clПакет не предназначен для использования больше. Вы должны всегда использовать cl-libпакет вместо этого, который определяет функции с cl-префиксом ..
Malabarba
1
Я бы рекомендовал не использовать cl-values: это эмуляция «наилучшего усилия» CommonLisp, valuesно она не совсем совместима, поскольку все, что она делает, это возвращает список (то есть это своего рода ложь), и, по моему опыту, люди рано или поздно заканчивают тем, что манипулирование ими как списками (то есть нарушение абстракции): лучше использовать списки явно (и если вам не нравится pcase-let, то используйте cl-destructuring-bindвместо cl-multiple-value-bind).
Стефан
4

Кроме того cl-lib, в Elisp рекомендуется использовать пакет совместимости 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)))

Кроме pcase-let, есть также pcase-dolist, pcase-lambdaи pcaseсам по себе.

Стефан
источник