Default parameter opsional

26

Emacs Lisp tidak memiliki dukungan sintaksis untuk parameter opsional opsional yang tidak nol. Apa idiom yang disarankan untuk memasok parameter ini?

Untuk memperjelas poin saya, berikut ini adalah satu cara yang terlalu eksplisit untuk melakukannya.

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

Apa, jika ada, gaya yang disarankan?

Matthew Piziak
sumber

Jawaban:

24

Kecuali Anda menggunakan ekstensi Common Lisp seperti yang disarankan oleh @legoscia, Anda perlu memeriksa apakah argumen opsional sudah ditentukan. Perhatikan bahwa Anda tidak perlu menggunakannya di letsini. Ini sepertinya lebih idiomatis bagi saya:

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

Seperti yang disarankan dalam komentar, menggunakan unlessmungkin lebih disukai daripada or:

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

Juga dari komentar: gaya fungsional yang lebih murni akan digunakan let, seperti pada pertanyaan asli, tetapi Anda tidak perlu nama variabel yang terpisah:

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

Tentu saja, jika parameter opsional hanya diperlukan sekali Anda harus melakukan ini:

(defun my-command (a &optional b)
    (command-body a (or b default)))
glukas
sumber
7
-1: Saya tidak berpikir itu gaya yang baik untuk menggunakan ekspresi efek samping seperti setqdalam bentuk boolean "murni" seperti or. Menurut pendapat saya whensudah pasti lebih tepat di sini, tetapi umumnya letadalah ekspresi pilihan untuk membangun atau mengubah binding lokal. TKI, kode aslinya terlihat jauh lebih bagus untuk saya.
lunaryorn
3
Saya setuju bahwa sesuatu seperti (unless b (setq b default)mungkin lebih baik. Secara pribadi, saya pikir letberlebihan di sini karena bsudah lokal ke Internet defun.
glucas
3
Ini masalah selera, tapi saya lebih suka kode murni dan binding murni, yaitu letlebih dari bentuk efek samping seperti setq. Ini kode untuk parameter default, tetapi penggunaan liberal setquntuk mengubah variabel lokal membuat kode sulit dibaca dan diikuti. Saya pikir yang terbaik adalah menganggap semua ikatan lokal tidak berubah, dan hanya membuat ikatan baru dengan let. TKI, lebih memilih gaya fungsional daripada yang imperatif.
lunaryorn
22

Anda dapat menggunakan cl-defun, yang memungkinkan Anda menentukan nilai default untuk argumen opsional:

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

Nilai default, dalam hal ini default-b, akan dievaluasi setiap kali fungsi dipanggil.

legoscia
sumber