Поменяйте местами две переменные в Elisp

20

Предположим, у меня есть

(setq a 1 b 2)

Как я могу элегантно поменять значения aи bбез использования временной переменной?

PythonNut
источник
Хотя я помню операцию подкачки из примеров программирования много-много лет назад, я не думаю, что мне когда-либо была нужна такая операция подкачки. Так где вы находите, что вам нужна такая вещь?
Стефан
@ Стефан на этот раз я пишу функцию, которая принимает два аргумента, и я хотел бы убедиться, что первый аргумент является меньшим из двух.
PythonNut
1
@PythonNut, вы можете привязать первый аргумент к, (min a b)а второй к (max a b). Это одно из решений. Некоторые утверждают, что для этого требуется два сравнения, когда одного достаточно, это правильно. Вы можете справиться с одним сравнением еще более функционально, например, используя деструктурирующее связывание (cl-destructuring-bind (a . b) (if (< a b) (cons a b) (cons b a)) ...). Это другой способ.
Марк Карпов
1
@ Правда, но, по крайней мере для меня, это похоже на мух с ручными гранатами. cl-destructuring-bindэто невероятно мощный инструмент для этой работы.
PythonNut

Ответы:

18

Если память мне не мешает, и вы готовы ее использовать, cl-libто:

(cl-rotatef a b)

Обратите внимание, что это Common Lisp способ решения проблемы.

Марк Карпов
источник
20

Это элегантная идиома, которую я использую ;-).

(setq a  (prog1 b (setq b  a)))
Нарисовалась
источник
1
Эй, это аккуратно. Я буду помнить об этом, если производительность когда-либо будет проблемой.
PythonNut
1
Гениально и просто.
Имя
1
О, это не оригинально со мной, в любом случае. Но это, вероятно, основное использование, из которого я делаю prog1.
Дрю
1
Это в значительной степени то, что cl-rotatefмакрос расширяется до.
abo-abo
6

Если это целые числа:

(setq a (logxor a b))
(setq b (logxor a b))
(setq a (logxor a b))

:)

jtgd
источник
2
Для полноты вы также должны включить следующую классику: a = a + b, b = a - b, a = a - b. Перевод на Emacs Lisp, конечно :-D
Марк Карпов
1
Правда, и для полноты я укажу, что в asm или C трюк XOR работает для всего; регистры, память, целые числа, числа с плавающей запятой, структуры, строки (равной длины) ... В Лиспе я думаю только целые числа. Для больших блоков памяти хорошо не использовать временный буфер.
Jtgd
@jtgd: Для больших блоков памяти вы можете делать поменять сегмент за сегментом с небольшим буфером.
Климент