Зв'язуйте декілька значень безпосередньо зі списку, не зв'язуючи сам список


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

У звичайного 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).

Примітка : якщо ви подивитесь на відповідь SO, пов'язану вище, ви побачите, що емуляція MV зі списками, м'яко кажучи, неоптимальна (див. Також коментар @ Стефана нижче).


Чи є якась перевага використання multiple-value-bindзамість цього cl-multiple-value-bind(лише, здається, це підтверджено в посібнику gnu.org/software/emacs/manual/html_node/cl/Multiple-Values.html )?
Håkon Hægland

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сам по собі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.