実践Common lispを読み始めた-第5章 関数

SLIME不調

今日はSLIMEの調子がおかしい。

Polling "/var/folders/VA/(中略)/-Tmp-/slime.41395" .. 
(Abort with `M-x slime-abort-connection'.)

のままSLIMEが立ち上がらない。
再起動してもだめ。
何か情報でもないかなと思ってLispboxのページを見たら、aclのバージョンが8.1にバージョンアップしていた。入れ替えてしまおう。
直った直った。よかった。

関数定義

関数はdefunマクロで定義される。

(defun name (parameter*)
 "省略可能なドキュメンテーション文字列"
 body-form*)

関数の名前に使えるシンボルはC/C++よりも自由度が高い。
"->"なのとか使えるのか。でもC/C++文化圏にいた自分にとっては混乱する名前でしかないな。まだハイフンを使うのは気にならない。

でも関数定義でドキュメンテーション文字列が設定できるというのも意外な感じ。でも、javaでいうところのjavadocが言語仕様で決まっているようなものか。納得。

関数定義の本文のbody-formは任意のlisp式で構成される。フォームと式って同じものと思ってもよいのかな。

関数のパラメタリスト

  • &optional この後のパラメタはオプション &optionalの後ろに(変数名 値)をつけるとデフォルト値も設定できる。デフォルト値に別のパラメタを指定できるのは素敵。
>(defun foo (a b &optional c) (list a b c))
>FOO
>(foo 1 2)
>(1 2)
>(foo 1 2 3)
>(1 2 3)
>(foo 1 2 3 4)
>エラー
>(defun foo (a &optional (b a) (c 100)) (list a b c))
>FOO
>(foo 1)
>(1 1 100)
>(foo 1 10)
>(1 10 100)
  • &rest この後ろのパラメタに可変個の引数を格納する。
>(defun (a &rest b) (list a b))
>FOO
>(foo 1)
>(1 NIL)
>(foo 1 2 3 4 5)
>(1 (2 3 4 5))

&restの後ろのパラメタにはリストになわけだ。

  • &key この後ろのパラメタはキーワードパラメータ。キーワードに対応する値をセットするときには
(hoge :a 1)

みたいに":keyword"+値で設定する。キーワードに対応する値を設定しなかったらNILになる。

>(defun (&key a b) (list a b))
>FOO
>(foo)
>(NIL NIL)

じゃあ、ふつーにキーワードなしの値を入れたらやはりNILなのか?やってみよう。

>(defun (&key a b) (list a b))
>FOO
>(foo 1 1)
1 not a legal keyword arg.
   [Condition of type PROGRAM-ERROR]
(以下省略)

なるほど、引数はキーワード付きでないとだめらしい。

  • -supplied-p keyの値が設定されているかを示す変数。-pはpredicate(述語)の略?なんか:-pみたい。
  • パラメタは便利だけど、2種類以上組み合わせるのは注意したらいいよ。特に&keyとその他のキーワードの組み合わせはさけた方がよい。

関数の戻り値

lispの関数は最後の式を評価した値を戻り値にするのが普通だけど、途中で戻したい場合はreturn-fromという特殊オペレータを使えばよい。関数名を指定しないといけない理由がよくからないし面倒だ。
lispだとCほど頻繁に途中で抜けないらしいからまずは気にしないことにしよう。

データとしての関数または高階関数

関数をデータとして扱うにはfunction関数(または'#)を使う。こいつで関数オブジェクトをとれる。とった関数オブジェクトを通じて関数呼び出しするにはfuncall, applyを使う。

無名関数

lambda式を使って無名の関数を定義できる。javascriptのfunctionみたいなものかな。