cl-defun is an autoloaded Lisp macro in ‘cl-macs.el’.
# cl-defun は ‘cl-macs.el’ に自動ロードされる Lisp マクロです。
(cl-defun NAME ARGLIST [DOCSTRING] BODY...)
Define NAME as a function.
# NAME を関数として定義します。
Like normal ‘defun’, except ARGLIST allows full Common Lisp conventions,
and BODY is implicitly surrounded by (cl-block NAME ...).
# ARGLIST が完全な Common Lisp 規則を許可し、BODY が (cl-block NAME ...)
# で暗黙的に囲まれていることを除いて、通常の「defun」と同様です。
The full form of a Common Lisp function argument list is
# Common Lisp 関数の引数リストの完全な形式は
(VAR...
[&optional (VAR [INITFORM [SVAR]])...]
[&rest|&body VAR]
[&key (([KEYWORD] VAR) [INITFORM [SVAR]])... [&allow-other-keys]]
[&aux (VAR [INITFORM])...])
VAR may be replaced recursively with an argument list for
destructuring, ‘&whole’ is supported within these sublists. If
SVAR, INITFORM, and KEYWORD are all omitted, then ‘(VAR)’ may be
written simply ‘VAR’. See the Info node ‘(cl)Argument Lists’ for
more details.
# VAR は、再帰的に分解用の引数リストに置き換えることができます。これらの
# サブリスト内では「&whole」がサポートされています。 SVAR、INITFORM、
# KEYWORD をすべて省略した場合、「(VAR)」は単に「VAR」と記述できます。詳
# 細については、Info ノード「(cl)Argument Lists」を参照してください。
(cl-defuntest-clfun (a b &rest args &optional e f)
(list a b c d e f)) ;;Malformed argument list ends with: (&optional e f)
(cl-defuntest-clfun (a b &key c d &optional e f)
(list a b c d e f)) ;;Malformed argument list ends with: (&optional e f)
(cl-defuntest-clfun (a b &key c d &rest args)
(list a b c d args)) ;;Malformed argument list ends with: (&rest args)
(cl-defuntest-clfun (a b &aux (z (+ a b)) &optional c d)
(list a b c d z)) ;;Malformed argument list ends with: (&optional c d)
(cl-defuntest-clfun (a b &aux (z (+ a b)) &rest args)
(list a b c d z)) ;;Malformed argument list ends with: (&rest args)
(cl-defuntest-clfun (a b &aux (z (+ a b)) &key c d)
(list a b c d z)) ;;Malformed argument list ends with: (&key c d)
技術的にはどんな順番でも良さそうな物ですが、処理の順番としては自然な気もします。
同じ物(&~)を複数書いた場合は対応が分かれます。(Emacs 28.2時点)
(cl-defuntest-clfun (a b &optional c d &optional e f)
(list a b c d e f)) ;;OK!
(test-clfun 1 2) ;;Invalid function
(cl-defuntest-clfun (a b &optional (c 100) d &optional e f)
(list a b c d e f)) ;;OK!
(test-clfun 1 2) ;;OK!
(cl-defuntest-clfun (a b &rest rest1 &rest rest2)
(list a b rest1 rest2)) ;;Malformed argument list ends with: (&rest rest2)
(cl-defuntest-clfun (a b &rest rest &body body)
(list a b rest body)) ;;Malformed argument list ends with: (&rest body)
(cl-defuntest-clfun (a b &key c d &key e f)
(list a b c d e f)) ;;OK!
(test-clfun 1 2) ;;OK!
(test-clfun 1 2 :c 3 :d 4 :e 5 :f 6) ;;OK!
(cl-defuntest-clfun (a b &aux (c (+ a b)) &aux (d (* a b)))
(list a b c d)) ;;OK!
(test-clfun 2 3) ;;OK! (2 3 5 6)
(cl-defuntest-clfun (a b &optional)
(list a b)) ;;OK
(test-clfun 1 2) ;;OK
(cl-defuntest-clfun (a b &key)
(list a b)) ;;OK
(test-clfun 1 2) ;;OK
(cl-defuntest-clfun (a b &optional&key&aux)
(list a b)) ;;OK
(test-clfun 1 2) ;;OK
(funcall
(let ((a 2))
(cl-defuntest-clfun (b &optional (c (* a b)))
(list a b c))
#'test-clfun)
3)
;;=>;;レキシカルバインディング時: (2 3 6);;ダイナミックバインディング時: Symbol’s value as variable is void: a
(cl-defuntest-clfun (b &optional (c (* a b)))
(list a b c))
(let ((a 2))
(test-clfun 3)))
;;=>;;レキシカルバインディング時: Symbol’s value as variable is void: a;;ダイナミックバインディング時: (2 3 6)
引数の左側は参照できて右側は参照できません。
(cl-defuntest-clfun (a &optional (b (* a c)) &aux (c 100))
(list a b c))
(test-clfun 2) ;;Symbol’s value as variable is void: c
(cl-defuntest-clfun (&key a b c d)
(list a b c d))
(test-clfun :d 345 :b 234 :a 123 :z 999) ;;Keyword argument :z not one of (:a :b :c :d)
(cl-defuntest-clfun (&key a b c d &allow-other-keys)
(list a b c d))
(test-clfun :d 345 :b 234 :a 123 :z 999) ;;=> (123 234 nil 345)
または呼び出し側で許可させることも出来ます。
(cl-defuntest-clfun (&key a b c d)
(list a b c d))
(test-clfun :d 345 :b 234 :a 123 :z 999 :allow-other-keys t) ;;=> (123 234 nil 345)
(test-clfun :allow-other-keys t :d 345 :b 234 :a 123 :z 999) ;;=> (123 234 nil 345)
(test-clfun :allow-other-keys nil :d 345 :b 234 :a 123 :z 999) ;;Keyword argument :z not one of (:a :b :c :d)
&optionalと&keyを同時に指定した場合
&optionalと&keyの両方が引数リストにある場合は注意が必要です。
例えば次のような書き方は問題ありませんが……
(cl-defuntest-clfun (a b &optional c d &key e f)
(list a b c d e f))
(test-clfun 1 2 3 4 :e 5 :f 6) ;;=> (1 2 3 4 5 6)
(test-clfun 1 2 3 4) ;;=> (1 2 3 4 nil nil)
(test-clfun 1 2 nil nil :e 5 :f 6) ;;=> (1 2 nil nil 5 6)