Common Lispの関数で色々な引数
Common Lispではいろいろな引数の渡し方がある。下の例は普通の関数の定義。
普通の関数
CL-USER> (defun foo (a b c d) (format t "a=~a b=~a c=~a d=~a" a b c d)) FOO CL-USER> (foo 1 2) ; 引数が足りない ; Evaluation aborted. CL-USER> (foo 1 2 3) ; これも引数が足りない ; Evaluation aborted. CL-USER> (foo 1 2 3 4) ; 引数の数が妥当なので以下の出力が得られる a=1 b=2 c=3 d=4NIL CL-USER>
オプショナルパラメータ
引数を省略するような時はオプショナルパラメータとして定義しておく。そうすると常に決められれた数の引数をとりたくないときは省略することが出来る。これにはオプションとしたい引数の前に「&optional」をつけて定義する。
下の例は、引数のa,bは必須で、c dに関してはオプションとなるので指定してもしなくてもよい。
CL-USER> (defun foo (a b &optional c d) (format t "a=~a b=~a c=~a d=~a" a b c d)) FOO CL-USER> (foo 1) ; 必須パラメータのbがしていされてないので、これはエラー ; Evaluation aborted. CL-USER> (foo 1 2 3) ; オプショナルパラメータのcを省略した場合 a=1 b=2 c=3 d=NILNIL CL-USER> (foo 1 2 3 4); 全部指定した場合 a=1 b=2 c=3 d=4NIL
また、オプショナルパラメータにはデフォルト値も設定することが出来る。
CL-USER> (defun foo (a b &optional (c 99) (d a)) (format t "a=~a b=~a c=~a d=~a" a b c d)) FOO CL-USER> (foo 1 2) a=1 b=2 c=99 d=1NIL
(c 99)とすることで省略された場合99という値がcに設定され、(d a)とすることで、省略された場合dにはaに設定された値が入る。
(d c)としてオプショナルパラメータの値をデフォルトとすることも出来た。こんな感じ。
CL-USER> (defun foo (a b &optional (c 99) (d c)) (format t "a=~a b=~a c=~a d=~a" a b c d)) FOO CL-USER> (foo 1 2 3) a=1 b=2 c=3 d=3NIL
レストパラメータ
可変の引数を渡したいときは「&rest」を利用する。下の例では変数「values」引数として渡された値がリストとして設定されている。
CL-USER> (defun foo (&rest values) (format t "~a" values)) FOO CL-USER> (foo 1 2 3 4) (1 2 3 4)NIL CL-USER> (foo 1 2 3 4 5 6 7) (1 2 3 4 5 6 7)NIL
キーワードパラメータ
これはよく使いそうな感じ。引数にキーと値のペアを指定して渡す事が出来る。「:key value」と言った感じ。
CL-USER> (defun foo (&key a b c d) (format t "a=~a b=~a c=~a d=~a" a b c d)) FOO CL-USER> (foo :a 10) a=10 b=NIL c=NIL d=NILNIL CL-USER> (foo :a 10 :b 20) a=10 b=20 c=NIL d=NILNIL CL-USER> (foo :d 40 :a 10 :c 30 :b 20) a=10 b=20 c=30 d=40NIL
「:a 10」とすることで変数aに10を設定している。3つ目の例では引数の順番を変えているが「:キー 値」と変数に値を割り当てているため問題なく出力される。また、引数を省略しても問題ない。
またオプショナルパラメータと同様にデフォルト値も指定することが出来る。
CL-USER> (defun foo (&key (a 1) (b 2) (c 3) (d c)) (format t "a=~a b=~a c=~a d=~a" a b c d)) FOO CL-USER> (foo) a=1 b=2 c=3 d=3NIL
RubyやJavaScriptでもこのパターンがよくでてくる気がするな。やっぱ、関数に何を渡しているか明示することで間違いも少なくなるし、変更にも強くなるからなんだろうな。
大事な事を忘れてた。てかこれを忘れそうだからメモしとこうと思ったのに。。
オプショナルパラメータとキーワードパラメータでは、「パラメータの名前 + supplied-p」という変数を定義すると、そのパラメータに値が設定された時はT(真)になり、設定されなかった場合はNIL(偽)となる。
CL-USER> (defun foo (&key (a 1) (b 2) (c 3) (d c d-supplied-p)) (format t "a=~a b=~a c=~a d=~a d-supplied-p:~a" a b c d d-supplied-p)) FOO CL-USER> (foo :a 10 :b 20 :c 30) ; dを省略した場合、d-supplied-pはNIL a=10 b=20 c=30 d=30 d-supplied-p:NILNIL CL-USER> (foo :a 10 :b 20 :c 30 :d 30) ; dを明示的に設定した場合 d-supplied-pはT a=10 b=20 c=30 d=30 d-supplied-p:TNIL
dにはデフォルト値と同じ30を指定しているけど、明示的にしていたってことでd-supplied-pはT(真)となる。
なかなか、おもしろい。