Opcjonalne wartości domyślne parametrów

26

Emacs Lisp nie ma wsparcia syntaktycznego dla domyślnych parametrów opcjonalnych innych niż zero. Jaki jest zalecany idiom do dostarczania tych parametrów?

Aby wyjaśnić moją kwestię, oto jeden nadmiernie wyraźny sposób na zrobienie tego.

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

Jaki jest zalecany styl?

Matthew Piziak
źródło

Odpowiedzi:

24

O ile nie używasz rozszerzeń Common Lisp zgodnie z sugestią @legoscia, musisz sprawdzić, czy podano opcjonalny argument. Pamiętaj, że tak naprawdę nie musisz lettutaj używać . Wydaje mi się to bardziej idiomatyczne:

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

Jak sugerowano w komentarzach, użycie unlessmoże być lepsze niż or:

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

Również z komentarzy: należy zastosować bardziej czysty styl funkcjonalny let, jak w pierwotnym pytaniu, ale nie potrzebujesz osobnych nazw zmiennych:

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

Oczywiście, jeśli opcjonalny parametr jest potrzebny tylko raz, powinieneś po prostu to zrobić:

(defun my-command (a &optional b)
    (command-body a (or b default)))
glucas
źródło
7
-1: Nie sądzę, że dobrym stylem jest stosowanie efektów ubocznych, takich jak setq„czysta” boolowska forma or. Moim zdaniem whenjest to zdecydowanie bardziej odpowiednie tutaj, ale ogólnie letjest to wyrażenie wyboru w celu ustanowienia lub zmiany lokalnych powiązań. IOW, oryginalny kod wygląda dla mnie o wiele ładniej.
lunaryorn
3
Zgadzam się, że coś takiego (unless b (setq b default)może być lepsze. Osobiście uważam, że letjest tutaj zbędny, ponieważ bjest już lokalny dla defun.
glucas
3
To kwestia gustu, ale wolę czysty kod i czyste powiązania, tj. Bardziej letniż efekt uboczny, taki jak setq. Jest to kod parametru domyślnego, ale swobodne użycie setqdo zmiany lokalnych zmiennych powoduje, że kod jest trudny do odczytania i śledzenia. Myślę, że najlepiej rozważyć wszystkie lokalne powiązania jako niezmienne i ustanawiać tylko nowe let. IOW, wolę styl funkcjonalny od nadrzędnego.
lunaryorn,
22

Możesz użyć cl-defun, co pozwala określić wartość domyślną dla opcjonalnych argumentów:

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

W tym przypadku wartość domyślna default-bbędzie oceniana przy każdym wywołaniu funkcji.

legoscia
źródło