Необязательный параметр по умолчанию

26

Emacs Lisp не имеет синтаксической поддержки значений по умолчанию для необязательных параметров. Какова рекомендуемая идиома для предоставления этих параметров?

Чтобы прояснить мою точку зрения, вот один из слишком явных способов сделать это.

(defun command (a &optional supplied-b)
  (let ((b (or supplied-b default-b)))
    (command-body a b)))

Какой, если вообще, рекомендуемый стиль?

Мэтью Пизиак
источник

Ответы:

24

Если вы не используете расширения Common Lisp, как предложено @legoscia, вам нужно проверить, был ли указан необязательный аргумент. Обратите внимание, что вам не нужно использовать letздесь. Это кажется мне более идиоматичным:

(defun command (a &optional b)
  (or b (setq b default))
  (command-body a b))

Как предлагается в комментариях, использование unlessможет быть предпочтительным для or:

(defun command (a &optional b)
  (unless b (setq b default))
  (command-body a b))

Также из комментариев: более чистый функциональный стиль будет использоваться let, как в оригинальном вопросе, но вам не нужны отдельные имена переменных:

(defun my-command (a &optional b)
  (let ((b (or b default)))
    (command-body a b)))

Конечно, если необязательный параметр нужен только один раз, вы должны просто сделать это:

(defun my-command (a &optional b)
    (command-body a (or b default)))
glucas
источник
7
-1: я не думаю, что это хороший стиль - использовать выражение с побочными эффектами, как setqв «чистой» булевой форме, например or. На мой взгляд, whenздесь определенно более уместно, но обычно letэто выражение выбора для установления или изменения локальных привязок. IOW, оригинальный код выглядит намного лучше для меня.
lunaryorn
3
Я согласен, что что-то вроде (unless b (setq b default)может быть лучше. Лично я думаю, что letздесь избыточно, потому что bэто уже локально для defun.
глюк
3
Это дело вкуса, но я предпочитаю чистый код и чистые привязки, т. letЕ. Как побочную форму setq. Это код для параметра по умолчанию, но либеральное использование setqдля изменения локальных переменных затрудняет чтение и следование коду. Я думаю, что лучше всего считать все локальные привязки неизменными и устанавливать только новые let. Я хочу отдать предпочтение функциональному стилю, а не императивному.
lunaryorn
22

Вы можете использовать cl-defun, что позволяет указать значение по умолчанию для необязательных аргументов:

(cl-defun command (a &optional (b default-b))
  (command-body a b))

В этом случае значение по умолчанию default-bбудет оцениваться при каждом вызове функции.

legoscia
источник