octahedron

LemとSKKとCommon Lispでたたかうプログラマのブログ

どうしてぼくはCommon Lispを書くのか

 この記事は技術記事ではありません。自己分析のための独白のようなものです。

この記事を書いた経緯

 雲が空高く流れる季節となったこのころ、二〇一七年十月末日をもって、ぼくは無職になりました。こうなると平日のほぼ全ての時間、独りで過ごすことになり、さまざまなことが頭をよぎります──人生のことや、うず高く積まれた積ん読のこと(読め)、懐具合のこと、身体のこと、年齢のこと……。
 そんな中でもとくに頭を悩ませるのは、やっぱり仕事のことです。

 次の職場でうまくやっていけるかしら──
 ぼくは何を仕事としたいんだろう──
 仕事とは──

 そういう悩みを書き出すことで整理し納得や気付きなんかを得るために、この記事を書いています。

 ここでは、なんでぼくはCommon Lisp固執しつづけ、時に他の言語をディスってしまうほどCommon Lispが大好きなのか、将来もCommon Lispをやりたいのか、を考えていきます。
 まずは、なんでCommon Lispはじめたんだっけという回想からやってみます。

なんでCommon Lispを始めたか

 中学生のころから、プログラミングをすることについて、興味津々でした。
 きっかけは「自分でゲームをつくれるなんて楽しそう!」程度のものだったと思います。あるいは、鈴木光司の『ループ』を読んで、人工生命の分野に興味が芽生えたということもあったと思います。が、当時できたのはせいぜい、技術家庭の教科書にBASICが載っているのを見、家のパソコンに「N88互換BASIC」というソフトを導入して、ちんまりとした描画プログラムをつくって遊ぶことくらいでした。
 まだその当時はLISPのLの字も知りませんでした。

 また、Wikipediaを知り、いろいろな情報が簡単に手に入ることを学びます。コンピュータと人工生命への興味はとても高まっていましたから、それらについて記事から記事へと関連を辿って貪るように読んでいた記憶があります。その中で、確実にLISPについて触れたはずですが、まだLISPを特別に意識はしていませんでした。せいぜい「チューリング機械というものがあるのか、なんかよくわからんけどカッコイイ!」くらいのものでした。

 そうしてC言語は読み書きできないまま、大学に入ります。
 大学では、RoboCupに関するサークルに入り、AIBOを動かすC++ソースコードGNU/Linuxに触れました。ちなみにC++は未だによくわかりません。
 そこでアクチュエータの制御やカメラの画像認識、行動のタスクスケジューリングを行うコードに触れ、また講義で人工知能系の基礎を学ぶ中で、人工知能からは興味が離れていきました。当時のぼくにはどれもレベルが高すぎ、泥臭い数学が手に負えないという、強い実感があったのかもしれません。あるいは、大好きなSFに出てくる「強いAI」には程遠いと思ったからかも。

 そんなぼくがLISPとファーストコンタクトするのは、大学の文化祭でした。
 文化祭で、図書館が破棄する本の無料開放をやっていました。当時から本を所有することが大好きで、もちろんお金がなかったぼくは、タダで貰えるのならと並べられている古い本を物色していました。その中にあったのがこの本です。

 当時、LISPPascalFORTRANなどと同じくいわゆる古代の言語であり、コンピュータの歴史の中で重要な役割を演じてきた言語である、と認識していました。歴史的に重要な言語であるなら、学ぶ価値があるだろう、というふうに考えたわけです。(その考え方でCOBOLに手を出さなくてよかった!)
 この『これがLISPだ!』、LISPの基礎からエキスパートシステムの構築までを解説しています。いま思うとちょうどいい本なのですが、マクロの応用あたりからだんだん理解が難しくなっていったのを覚えており、読破はできませんでした。処理系で動かさず、紙の上だけで読んでいたからかもしれません。
 とはいえ、ここでLISPの基礎概念に慣れ親しみ、Common Lispの世界に突っ込む準備はできていたわけです😏

 そして大学院へ入ります。
 大学と大学院が違いあまり知り合いがいなかったため、講義の合間は図書館で本を物色していました。コンパイラのドラゴンブックとかラムダ計算の本とかパラパラと眺めていた覚えがあります。同じ区域のコンピュータ関連書籍を眺めていると、そこにはこの本が。

 LISPの本自体はそこに何冊かあったのですが、この本の目次を見て驚きました。他の本はエキスパートシステム等現実感のないものを終わりのほうで書くのですが、音楽配信サーバの作成は本当に「実用」でした。
 で、始めのほうを読んでみるわけです。

1億マイルも離れた100万ドルもするハードウェアで走っている動作中のプログラムのデバッグは非常に面白い経験だった。問題の発見と修正には、宇宙船で走っていたread-eval-printループがなくてはならない貴重なものだった。

 当時、LISPを始めるにあたってSchemeCommon Lispか、どちらにしようか迷っていました。が、この文句と、バイナリファイルをパースする章を読んで、Common Lispを始める決意を固めたのを覚えています。

 はじめた決め手は『実践Common Lisp』に違いありません。
 しかしそれを手に取ったのは、『これがLISPだ!』を読んでいてLISPにちっぽけながら知見があったからだと思っています。そして、人工知能・人工生命に興味を持っていたから、LISPについて知ろうと考えました。
 あのころ土日の昼間を外にも行かずWikipediaばかり眺めて過ごした日々よ、ありがとう。

どうしてCommon Lispなのか

 とはいえ、その遍歴の中でさまざまな言語の名を聞き、実際に触れてみたりもしています。JavaとかPythonとかHaskellとかJavaScriptとかRubyとか。でもなんで未だにCommon Lispを使い続けているのでしょう。
 ぼく自身ふしぎなので、ぼくがCommon Lispを愛して止まない理由について、考えてみようと思います。

規格で仕様が定められている

 ご存知のとおり、Common LispANSIで仕様が定められています。このことが意味するのは、どんな処理系のどんなバージョンでも、Common Lispを名乗る限りにおいて一定の動作をすることが保証されていることです。
 つまり、言語仕様が進化を遂げていき、過去に書いたコードが(ライブラリバージョンのせいではなく)言語仕様の意味で不正なコードになって動かなくなるということがない、ということです。

 たとえば、Common Lispにおける実験的な遅延シーケンス(ジェネレータなどが提案された)のライブラリcl-series は2000年ごろに書かれたライブラリのようですが、いまでもばっちり動きます。同じく規格のあるC言語でも古いけど現役のコードがありそうですが、RubyPythonで同じようにいくでしょうか?

 過去の資産がいつまでも有効であることは、Common Lispの大きな魅力です。

構文について覚えることが少ない

 ご存じのとおり、Common Lispは──というかLISPは──S式でコードを記述します。LISPの構文について覚えておくべきことは少しだけで、それは括弧に始まり括弧に終わり、先頭にやりたいことを書く、ただそれだけです。

 Common Lispでは、LISP特有の伝統的マクロによって新たな構文が導入されるとき、新しい構文要素についていちいち気を払う必要はありません。新しい構文要素に目を慣らすことなく、その構文が何をするのかにだけ気を向けることができます。他人のコードを読んでいるときにかつて出会ったことのない構文を見て(たとえば$などの半角記号なので)調べかたに困る、というようなことがありません。

 もちろん、リーダマクロが導入されたときは例外です。

動的に環境にアクセスできるため開発がしやすい

 ご存じのとおり、Common Lispでは実行中のプログラムが参照する関数の定義を、実行時に差し替えることが可能です。たとえば、実行中のグラフィックスプログラムが参照している描画関数の定義を変更し、REPLから流し込んでやることで、実行中のプログラムの描画内容を即座に変更する、ということが可能です。また、GNU Emacs用のプラグイン、SLIMEによってREPLの機能が大幅に増強され、開いているソースコードに書かれた関数の定義をCommon Lispのプロセスに送る、ということもできます。

 そのためプログラムを書くとき、まずは一番小さな部品をREPLで組み立て、次に別の小さな部品をREPLで組み立て、ということを繰り返していき、最後に組み上げるというボトムアッププログラミングの方法でつくり上げていくことができます。トップダウン的にコードを書いていくと、どうしても初めて動かしたときにてんこ盛りのバグへ対処せねばならず、気持ちを保つのにぼくは苦労します。

 単に対話的につくり上げていくスタイルのほうがぼく自身に合っているだけかもしれませんが、それを究極に推し進めたCommon Lispは、そんなぼくにとって最高の道具です。

将来もCommon Lispをやっていきます

 好きな点が思ったよりもたくさん出てきました。
 新しい風を感じたくて、あるいは知らない概念を学びとるために、別な言語を学び始めることは何度かありましたし、これからもあると思いますが、ぼくは上記の理由からいつかCommon Lispに戻ってきてしまうのだろうなあ、というのが整理してみての実感です。もしぼくが別な言語に完全に移行するときがくるとしたら、その言語はきっとCommon Lispを遥かに越えた言語であるに違いなく、それはそれでいいのかもしれません。

 なので/ですが、今ぼくはCommon Lispが一番好きです。