ホーム » Lispはなぜ神の言語と呼ばれるのか

Lispはなぜ神の言語と呼ばれるのか


2021/04/25

もともとは川合史朗氏の記事を紹介して終わっていたのですが、大幅に追記しました。

—-

古から存在するプログラミング言語Lisp。その通り名の一つに「神の言語」というものがある。

なんという甘美な響きだろうか。この名前だけで男子中学生は全員習得することを決心するだろう。そのくらいインパクトのある名前である。文部科学省はプログラミング教育を推進するにあたって、この通り名を公式に採用することを真剣に検討されると良い。

さて、「神の言語」の勉強を始めてみて驚くだろう。どのあたりが神なのかよくわからないのだ。たしかに丸括弧は多い。多いが、それと神との関連性はよくわからない。

何か土着の信仰の話なのだろうか?そう戸惑うのも無理はない。

私自身、前からこのフレーズは聞いたことがあったが、あまり理解していなかった。そこで今回改めて調べてみたので共有しようと思う。

「神の言語」の由来

そもそも、Lispは神の言語だと誰が言い出したのか?どうやら海外でそのような歌が作られたというのが始まりのようである。Bob Kanefskyという方が”Eternal Flame”というタイトルで、2000年にリリースされたそうである。いきなり濃い話である。Pythonの歌とか、C++の歌とか聞いたことがあるだろうか?[1]この手の話で私が他に知っている唯一の事例はシュレディンガー音頭だ。

あまりに狂信的なエピソードなので、やっぱり土着の信仰なのかもしれないと少し心配になってくるが、まずは中身を見てみるとしよう。

日本語訳を掲載されているページがあったので紹介する。

Lispは神の言語

C、C++、Perl、Fortran、Java、COBOL、APLが引き合いに出され、神はこれらの言語を全て知っているが、その上でLispを選んだ、Lispで世界の全てを作った。なぜなら神には締め切りがあって6日間で世界を作らなければならなかったから、というのが要旨だ。

6日間で世界を作るというのが難しい仕事であるということは想像に難くない。私なら少なく見積もっても3週間はかかるだろう。そのような難しい仕事を実現できるのは、神の力を持ってしても道具を選ぶ必要があり、その道具がLispであるということだ。それにしても納期6日というのはいくらなんでもひどい。神も大変なんだな。

歌詞の中ではそれ以上の理由は述べられていないので、別の文献に当たる必要がある。

Lispはなぜ難しい仕事に向いているのか

Lispがなぜ難しい仕事に向いているのか、ということについては、下記に紹介されているページで明快に記述されている。Gaucheの作者である川合史朗氏の名文である。GaucheというのはSchemeの処理系で、SchemeというのはLisp族の主要な一派である。私はこのような素晴らしい文章を読むと定期的に読み返してしまう。

Lisp:S式の理由

Schemer’s way

ちゃんと読んだだろうか?多分、ちゃんと読んだ人は面白くて別の記事も読み始めたことだろうし、きっとそちらの方が有意義だろう。なので、私の記事に戻ってくるのはそのうちでいいのだが、時間が空いた時に私の話も聞いて欲しい。

さて、この世の中でプログラムで解決する課題は大きく二つに分かれる。解くべき問題が明確になっていて、あとはコンピュータにプログラムを書くだけ(それだってとても難しい)という問題と、解くべき問題すら明確になっておらず、プログラムを作りながら何を解けばいいかを理解していくような問題である。

当然、前者の問題が世の中の圧倒的多数を占めていて、後者のような難しい問題はほんの少しである。[2]いや実際には後者のような問題はたくさんあるが、時間とお金の投入が許されるのは主に前者だというだけかもしれない。

後者のような問題の代表例として、人工知能の開発のような問題が考えられる。最近では人工知能というのはパターンマッチであるということで相場が決まった感があるが、昔はもっといろいろ試行錯誤されていたらしい。当時、人工知能の研究者の間でメインで使われていたのがLispだったので、Lispとは人工知能向けの言語だという言説すらある。

後者のような問題領域でLispがなぜ有効なのか、ということを川合史朗氏が述べられているのが先ほどのページである。

もちろん世界を作るというのも後者に属する問題なので、神もLispを使っているのだ。これがLispが神の言語と呼ばれている理由である。

ドメイン特化言語

と、ちょっと前まではここで本文を終えていたのだが、やはりもう少し補足しておこう。蛇足かもしれないが、私自身の言葉でも語りたくなってきたのだ。

さて、Lispについて語る前に「ドメイン特化言語」というキーワードを紹介しておきたい。ドメイン特化言語とは、文字通りドメインに特化した言語のことである。ドメインとは何か。これは日本語で言うと「問題領域」である。アプリケーションが作られる時、そこにはほとんど常に解決すべき問題が存在する。なぜなら、(同語反復のようなものだが)問題を解決するためにアプリケーションが作られるからだ。

例えば、数式処理を行うアプリケーションがあるとする。MathmaticaとかMapleみたいなアプリケーションだ。この場合、問題領域は数式の処理となる。例えば、会計のアプリケーションがあるとする。SAPみたいなアプリケーションだ。この場合、問題領域は会計の処理となる。

数式を処理するためには、例えば微分の法則だとか、多項式を因数分解する手続きだとか、そう言ったことを知っている必要がある。会計を処理するためには、例えば財務諸表はどのようなルールで作成されるかだとか、購入金額がいくら以上の物品が固定資産として計上されるだとか、そう言ったことを知っている必要がある。

これらはプログラミングとは全然関係のないレベルの話である。その問題はソフトウェアで問題を解決するか否かに関わらず存在する問題であり、我々はその問題を解決する手段としてソフトウェアを構築している。このように、アプリケーションが解決すべき対象の問題やその周辺知識のことを「ドメイン」と呼ぶ。そして、各ドメインに特化したプログラミング言語のことを「ドメイン特化言語」と呼ぶのだ。

通常のプログラミング言語は「汎用言語」である。ある程度の向き不向きはあるものの、大体どのような領域のアプリケーションにも適用できるのが汎用言語だ。C言語は汎用言語だ。C言語で数式処理のアプリケーションをつくることもできるし、会計処理のアプリケーションを作ることもできる。すごいぞC言語。がんばれC言語。

ドメイン特化言語というのは汎用言語の対になる概念だ。ドメイン特化言語は特定のドメインに特化された言語なので、その領域の対象外のアプリケーションを作ろうと言うのは愚かな行為だし、それどころか不可能であることも多い。ドメイン特化言語の有名な例としては、リレーショナルデータベースシステムに使われる「SQL」という言語がある。SQLはデータベースを操作することに特化した言語だ。SQLを使ってデータベースのデータを検索したり更新したり削除したりするのは驚くほど簡単だ。SQLの一例をお目にかけよう。

select 商品名, 売上金額 from 売上データ where 売上日 = '2021-01-01'

これは「売上データから2021年1月1日の売上を対象に、商品名と売上金額を取得しなさい」という意味である。SQLの知識がなくとも、そんなものかなと読み取れるようなものだ。しかしデータベースは実際には、指定されたSQLを実行するために極めて複雑な処理を行なっている。データベースというのは結局は巨大なバイナリデータであることが多い。そこから指示された通りのデータを取得するために、データが格納されている領域を特定し、その中のどの項目が条件に指定されているかを判定し、条件に合致するデータを抽出する。もちろんそれだけでは十分ではない。データベースは高速に動作することが求められる。ユーザーの入力した条件の意味を変えない範囲で変更し、最速でデータを取得できるように工夫しなければならない。実際にデータの取得をする前段階でだ。もちろん複数ユーザーによる同時アクセスの考慮も必要だ。データを取得している最中に、他のユーザーがデータを書き換えたらどうなる?あるいは、他のユーザーがデータを更新している最中にデータを取得しようとした時は?変更前の値が欲しいこともあるだろうし、他のユーザーのデータの更新が完了するのを待ちたいかもしれないし、多少のデータのずれはいいから一刻も早くデータが欲しいこともあるだろう。そんなニーズに答えられる柔軟かつ一貫性のあるポリシーを提供する必要がある。それに耐障害性だって大切だ。突然サーバーがクラッシュして再起動した時、確定したはずのデータが一部失われていたら困ったことになる。だから確定したデータはすぐさま外部ストレージに保存したいところだが、ファイルIOはとびきり重たい部類の処理で、あまり頻繁に行うと動作が遅くなってしまう。つまり実データをストレージに書き込むことなく、データを確定させるための魔法のような機構が必要になる。それから、それから、それから、・・・

共有データに関するこのようなとても難しい問題は、汎用言語でカバーするには細かすぎる問題だが、個々のアプリケーションで解決するには重たすぎる問題だ。このような課題は通常ライブラリで解決するが、色々な言語のライブラリを片っ端から作るのも大変だ。なんと言ってもデータを共有したいというのはとても汎用的な課題であり、C言語で作るアプリケーションだろうが、Javaで作るアプリケーションだろうが、必要になるのは目に見えている。その度に新たなライブラリの使い方を覚えていく必要があるのかい?それならば、いっそのこと独立した専用の言語としてしまった方がいいのではないかい?そうだそうだ、そうしよう。ドメイン特化言語はこのような時に作られるのだ。

さて、いざドメイン特化言語をつくるとなると、通常は問題領域以外のことには興味のない専用のツールとして作ることになる。そのため、余計な構文は極力削ぎ落とされることになる。SQLというのはデータを操作するのに特化した言語なので、データを操作するための極少数の洗練された構文を持つ。主要な構文は、データの選択、更新、挿入、削除である。繰り返し文すら言語標準としては存在しない。[3] … Continue reading一言で言えば、「宣言的」なことが大きな特徴である。〇〇をしたいと宣言する構文だけが用意されているのだ。ユーザーはただ〇〇したいと宣言するだけでよく、それを実現するための難しいことはすべて言語処理系が担ってくれる。これはSQLに限った話ではなく、ドメイン特化言語は大体このような性質を持つ。汎用言語ではこれは難しい。ユーザーがしたい○○が無数にあるからだ。狭い問題領域に特化しているからこそ、厳密性を失うことなくシンプルで宣言的な構文を定義することができるのだ。

反面、用意されている構文以外のことはできないため、汎用性というパワーは失なわれている。SQLで世界を創造するのは、汎用言語で創造するよりも大変だろう。

神が世界を創造するにあたって、最初に行なったのは「世界を想像するためのドメイン特化言語」が存在するかどうかの調査であったことは想像に難くない。それであれば「光あれ」という構文だけで世界を構築することができたであろうからだ。始業が8時半とすれば、9時には動作確認まで終えて業務終了できただろう。しかし、そのようなドメイン特化言語は存在しなかった。だから6日かかったのだ。

最強の汎用言語とは何か?

ドメイン特化言語の話から一旦離れて、今度は汎用言語の話をしよう。最も汎用的な言語はなんだろうか?汎用的というのは「あらゆる問題領域に適用可能な言語」という意味である。C言語だろうか?それともJava、いやいやPythonだろうか?

どれも違う。どれも素晴らしく汎用的で、華々しい応用領域が広がっているが、「最も汎用的」というには程遠い。最も汎用的な言語とは何か?そう、「機械語」である。[4]一口に機械語と言ってもCPUごとにバリエーションはあるがそこには目を瞑って欲しい。あらゆる言語で書かれたあらゆるソースコードは、最終的には機械語に変換される。この地球上で書かれたありとあらゆる問題領域のアプリケーションが最終的には機械語に変換されている以上、もっとも汎用的な言語は機械語と言わざるを得ない。

汎用高級言語の意味

さて、機械語がもっとも汎用的な言語であるにも関わらず、その他の汎用言語が存在している理由はなんだろうか?それはもちろん、機械語というものが人間のためのものではなくコンピュータのためのものであるからだ。機械語で現代的な高度なアプリケーションを書くのは事実上不可能だ。そのため、機械語のパワーを失わない範囲で人間がさほどの苦労なく読み書きできるような言語が必要になる。それが高級言語だ。汎用高級言語というのは、機械語とドメイン特化言語の中間にあたる存在だ。機械語よりは宣言的だし、ドメイン特化言語よりは汎用的だ。

あるアプリケーションを作る時、問題領域の課題を解決するために、我々は高級言語でプログラムする。このとき初心者がやりがちなのは、問題領域の言葉を使わずにプログラムを書いてしまうという失敗だ。ありがちなのは変数名を、aとかbとかしてみたり、関数を全く使わずにベタ書きで書いてみたり、ということだ。良いプログラムというのは、問題領域の課題を解決するための言葉を使って書かれている。金融アプリケーションなら「利率」という名前の変数だったり、「複利計算処理」という名前の関数であるべきだ。物理シミュレーションを行うアプリケーションなら、粒子の3次元座標を意味する「Point」というクラスがきっとあるだろう。汎用言語というのはフラットな存在で、我々はその上に変数や関数やクラスを問題領域の言葉を使って定義している。これは汎用言語を問題領域専用の言語にカスタマイズしていると見なすこともできるのだ。我々は知らず知らずのうちに、自分専用のドメイン特化言語を作っているのだ。

既成のドメイン特化言語が存在しなければ、おそらくこれが最良のアプローチだ。[5]専用のドメイン特化言語を新たに作るという手もあるが、最初に飛びつくべきではない汎用の高級言語の上に、自分の取り組む問題領域専用の部品を作り、専用言語に作り替えていく。このアプローチを取る時には、どのような言語を選ぶといいのだろうか?一口に汎用の高級言語といってもいろいろな言語がある。そして、言語によっては汎用性にも色々と幅があるのだ。

あらゆる高級言語はドメインに依存している

ところで汎用高級言語というのは、高級にしたい、つまり人間に読み書きしやすい形にしたいというのが目的であって、汎用性を失わせることとは本来は無関係だ。しかし、実際には大なり小なり汎用性を失っているのが普通だ。これは、言語設計者は言語を作る際に何らかの使用用途を念頭において言語を設計しているというところに由来している。既存の言語が存在するところにあえて多大な苦労をして新規に言語を作る以上、現実的なニーズに応えるために作られているはずだ。そのニーズに応えるために、なんらかの味付けがされているのが普通だ。

C言語はハードウェアを制御することが得意だ。Fortranは数式を表現することが得意だ。PHPはHTMLを埋め込むことが得意だ。Visual BasicはWindows上でGUIアプリケーションを作ることが得意だ。Perlは文字列処理が得意だ。まあこの辺りの言語は、明らかに特定の利用用途を意識した言語なので、汎用高級言語の中でも、割合ドメイン特化言語寄りの言語と言えるだろう。このような言語も世界を創造するには不向きである。余計な遠回りを強いられてしまうだけだ。[6] … Continue reading

もっとドメイン的に中立的な言語もある。Java、Ruby、Python、Haskellなどだ。しかし、これらの言語はプログラミングパラダイムとしてはあまり中立的ではないのだ。JavaやRubyやPythonはクラスベースのオブジェクト指向というパラダイムを採用している。クラスベースのオブジェクト指向は、対象の問題領域を上手にクラス分割できた時にはうまくいく。しかし、クラスを横断するような仕組みは苦手である。Haskellは関数型というパラダイムを採用している。関数型は副作用のない純粋な処理が得意だ。そのため、対象の問題領域を、副作用のない純粋な部分と、副作用のある不純な部分に分けることができ、かつ、不純な部分が少なければうまくいく。そのため、副作用の少ない問題領域(構文解析など)は得意だが、副作用だらけの問題領域(Webブラウザなど)は苦手だ。

特定のプログラミングパラダイムに特化した言語は、直接的にはドメイン特化はしていないものの、間接的にはやはりドメイン特化している。対象の問題領域が、そのパラダイムが適用しやすいかどうかという問題があるのだ。

さて、世界を創造するという問題領域はどうなのだろうか?クラス分割しやすいだろうか?副作用は少ないだろうか?どんなパラダイムと相性がいいだろうか?時間に余裕があれば、いろいろ試してみてもいいだろう。しかし6日しかないのだ。言語選定に3日かけていては間に合わない。そして、どれもうまくいかないとなってしまっては目も当てられない。

今求められている(というよりは神が世界を創造した時に求められた)のは、特定のドメイン、特定のパラダイムを得意とする言語ではない。どのような問題領域にも適合させることができる言語、どのようなパラダイムも実現可能な言語なのだ。

なぜLispなのか

ようやくLispの話をしよう。神はなぜLispを選んだ(とBob Kanefsky氏は歌った)のだろうか?これにはLispの歴史と、今も受け継がれる思想を理解する必要がある。

さて、私は「言語設計者は言語を作る際に何らかの使用用途を念頭において言語を設計している」と言った。Lispは何を念頭に置いて設計されたのだろうか?Lispは実は何か実用的な用途を念頭に置いて設計された言語ではなかった。Lispは完全に理論的な存在として設計された。Lispは自分自身を評価することのできるevalという関数を持った仮想的な言語であり、これによってどのような計算がコンピュータ上で可能になるか、という学術上の興味をもとに設計された言語なのだ。設計者のジョン・マッカーシー(John McCarthy)は、Lisp言語を実装できるとは思っていなかった。当時大学院生だったスティーブ・ラッセル(Steve Russell)が実装して、ジョン・マッカーシーを驚かせたという逸話があるくらいだ。そのため、Lispは非常にドメイン的に中立であった。強いて言えば「計算そのもの」という非常に抽象的なものがLispの対象とする問題領域だったのだ。

Lispがドメイン的に中立なのはわかった。では、プログラミングパラダイムはどうだろうか?まずLispは1958年生まれで、Fortranと並ぶ最古の言語である。構造化プログラミングとか構造化定理という言葉が出てくるのはおおよそ1970年以降である。Lispの誕生した1958年という時代は、プログラミングパラダイムも何もない時代だった。当然、言語の誕生当初に特定のプログラミングパラダイムが意識されていたということはない。

そこまでは歴史の偶然の産物と言えようが、その後のソフトウェアパラダイムの発展の中で、特定のパラダイムに流されなかったのが素晴らしい。言語のコアはあくまでシンプルに保っておき、必要なものはライブラリとして実装する。いかなる処理でもライブラリとして実現できるように、言語のコアはシンプルながらも極めて汎用的かつ強力な機構(例えばマクロ)を持っておく。そのようにして、どのような問題領域であっても進化していけるような構造を保っておくのだ。これは言語コミュニティがこれまで守ってきた極めて重要な精神であり、おそらく相当意識的な努力が必要だったと思われる。

この精神が守られていたからこそ、Lispは今でも現役の言語であり続けているのだろうし、神も納期6日で世界を創造できたのだろう。

おまけ

どうせなのでもう少し語らせてもらいたい。

Lispがいかに素晴らしいかの話をする際に、前人未踏の領域ですごく役に立つという話はあるのだが、普通の領域ではLispはどうなのだろうか、という観点ではあまり語られていない気がするのである。結局普通の問題を解くことのほうが多いのだ。そんなときはどうすべきなのだろうか?

まず個人の趣味でコードを書く場合。これはもう答えは決まっている。好きな言語を使うべきだ。ただ、迷ったならLispを試して欲しい。括弧に目が慣れたらわかるが、Lispは美しい。Lispでのプログラミングはとても快適だ。美しい再帰関数を書けたときなど最高にスカッとする。それになぜかわからないが、私はしばらくLispを書いていないと、ある日急にLispのコードを書き殴りたくなるのだ。

一方、製品レベルのコードを書く場合、Common Lispにしろ、Schemeにしろ、ネックになるのがライブラリである。いや、私はライブラリの選択に困るほど本格的にLispを使いこなしてはいないのでよくわからないのだが、聞くところによるとあまり充実していないのだ。

こういったところを気にされるのであれば、Clojureという言語の存在を知っておくといい。この言語はJVM(Java Virtual Machine)上で動くLisp族の新星で、Javaのライブラリを呼び出せるのでとても安心感があるらしい。Mebabaseという現代的でかっこいいデータ可視化ツールがあるのだが、このツールがClojureで書かれていると知って私はすっかり嬉しくなってしまった。しかもPythonからわざわざ乗り換えたらしいのだ。Clojureがとても実用的な言語であることの証明だ。

私はLisp初心者がいきなりClojureというのは学ぶ内容が多すぎる気がするので、まずはSchemeかCommon Lispをやって、その後にClojureをしたほうがいいと思う。

何にせよ、Lispは「普通の」プログラミングでも役に立つぞと、声を大にして言いたいのだ。

References

References
1 この手の話で私が他に知っている唯一の事例はシュレディンガー音頭だ。
2 いや実際には後者のような問題はたくさんあるが、時間とお金の投入が許されるのは主に前者だというだけかもしれない。
3 厳密には再帰があるのでそれを応用して繰り返し処理を実現することはできるし、個々のリレーショナルデータベースのベンダが独自で拡張した構文としては存在することもあるが、普通に想像される意味では存在しない。
4 一口に機械語と言ってもCPUごとにバリエーションはあるがそこには目を瞑って欲しい。
5 専用のドメイン特化言語を新たに作るという手もあるが、最初に飛びつくべきではない
6 C言語などは、マシンパワーが非力だった時代にはこの選択肢しかなかったためドメイン的には中立的な立場にいたと思うが、現代においてはハードウェア制御に特化した言語という位置付けの印象だ。