LISt Processor?

元々,リストはLispの主要なデータ構造だった.事実,"Lisp"という名前は"LISt Processing"から来ている.しかしLispがこの歴史上の事実のせいで誤解されては困る.ポロシャツがポロ専用でないのと同様に,Lispはリスト操作用に生まれたのではない. 高度な最適化を施されたCommon Lispプログラムでは,リストを全く見かけないだろう.

Lispのデータ構造はcons特に単方向リストだけだと思っている人は多い.確かにSICPでは複雑なデータ構造を作るのにも(入れ子になった)リストやconsを使いまくっている.でもそうなったのはSICPがとりあえず手にしている語彙のみで概念を伝えようとしたからだ.また,確かにGNU Maxima等のソースコードにはcaddar等の(キモい)リスト操作関数が散見される.でもそれはソースコードの設計が時代遅れであるせいで,言語そのものが時代遅れであることを必ずしも意味しない.
Common Lispにはハッシュも(多次元)配列も標準で備わっている.というかC#Javaより自由度の高いOOPシステムが利用できる*1Schemeにだって配列がある*2 *3
残念ながらSunがJavaで推し進め,MSが.NETで模倣したような巨大で階層化された「クラスライブラリ」の思想は,現時点ではLisp陣営には(標準では)ない.でも決して相性が悪いわけではない.実際,Javaで実装されたScheme処理系ではJavaの標準ライブラリを呼び出せるものがある.基本構文や実行モデルに変更を加える必要はこれといってない*4.そこにLispの持って生まれた柔軟性が効いてると思う.
ところでPythonで書かれたMailmanをいじってたときに思ったが,誰が書いたとも知れん大規模なコードの中を歩き回るには,関数の引数に型で制限が嵌ってた方がよい.どうせ任意のデータが引数に来ることはまずなく,特定の構成を持つデータ(もしくは特定のクラスのインスタンス)だけなのだ.「このmailという名の引数に適用されたメソッドはどこで定義されたんだ?」なんてとき,mailとして渡し得るデータがMailDataのインスタンスのみと分かれば,定義の検索がかなり楽(でないとアヒャ).かと言って,コードの設計が固まらない段階では型宣言必須ではウザい*5.その辺も,オプショナルな型宣言を持つCommon Lispはうまく適応できると思う.
あーあ,なんでLispはもっと流行らないんだろう.いいと思うんだけどな.私がファンっぷりを発揮しても,どうせ計算機専門でない男の副業だから説得力ないしな...

*1:あくまでも標準ライブラリだが,もちろん処理系に統合して実行効率を上げる手もある.

*2:R5RSで言うヴェクタは任意のオブジェクトを格納できる必要があるので,ポインタの配列として実装することになるだろうけど.

*3:まぁ私がSchemeで複雑なデータ構造を設計するなら,貧弱なconsでなくlambdaで作られる環境を使いますね.クロージャをHashMapに使ってしまっても別にいいだろ.

*4:「クラスライブラリ」の実現に必要なのは単純な部分型(subtyping)システムで,言語全体をOOP向けにする必要はない.実際,現実世界のJavaC#, C++プログラムでどの程度「OOPしてる」かは怪しいものだ.そしてLispは動的型付けの言語だが,当然データには型があるので,CLOS等に依らずに「クラスライブラリ」を導入することすら可能.

*5:Haskell型推論のおかげで変数に型を指定する必要が少ないが,コミュニティは必ず関数のシグネチャを別に書くよう奨励しているようだ.これだと嬉しさ半減と思えるが,まぁ設計の目処が付くまで後回しにしてもよいんだろう.Ocamlの人にはどういう慣例があるのだろう. .cmi がインタフェイス宣言(Cで言うヘッダ)なんだよね.