Shammer's Philosophy

My private adversaria

&key の考察

LispでSocket作るときとか、他の様々な関数でもプロトタイプの中に&KEYというのがあることがある。ちょっとこれについての考察、というかメモ。

まず、自分でキーワードを使用した関数を定義するには、以下のようにする。

(defun keyword-func (&key a b c)
  (list a b c))

この例だと、キーワードを一つも引数に含まずにこの関数を呼び出すとエラーになる。

これを少し進化させてみる。

(defun keyword-func (&key (a 1) b c)
  (list a b c))

こうすると、引数にキーワードを一つも含まないで呼び出しても、a が 1 として扱われる。

CL-USER> (defun keyword-func (&key (a 1) b c) (list a b c))
KEYWORD-FUNC
CL-USER> (keyword-func)
(1 NIL NIL)

そして、キーワードにはもう一つ値を指定できる。上記例だと、a の 1 はデフォルト値の 1 なのか、実際に 1 を指定して呼び出されたのかが区別できない。その判定に使用される変数(?)も指定できる。

(defun keyword-func(&key (a 1 adefaultp) (b 2 bdefaultp) (c 3 cdefaultp)) 
  (list a adefaultp b bdefaultp c cdefaultp))

これを実行すると以下のようになる。

CL-USER> (keyword-func)
(1 NIL 2 NIL 3 NIL)
CL-USER> (keyword-func :a 10 :b 20 :c 30)
(10 T 20 T 30 T)
CL-USER> (keyword-func :a 10)
(10 T 2 NIL 3 NIL)
CL-USER> (keyword-func :b 2)
(1 NIL 2 T 3 NIL)
CL-USER> (keyword-func :a 1 :b 2 :c 3)
(1 T 2 T 3 T)
CL-USER> 

ただ、この書き方だと、キーワード引数以外の引数の扱いがよくわからなくなる。それについてはまた別の機会にやってみる。