Lispを異ならせたもの
2001年12月(2002年5月改訂)
(この記事はLL1メーリングリストでのいくつかの質問に応えて書かれた。現在はRevenge of the Nerdsに組み込まれている。)
McCarthyが1950年代後半にLispを設計したとき、それは既存の言語からの根本的な離脱であり、その中で最も重要なのはFortranだった。
Lispは9つの新しいアイデアを具体化した:
1. 条件分岐。 条件分岐はif-then-else構文である。我々は今これを当然のことと思っている。これらはLispの開発過程でMcCarthyによって発明された。(当時のFortranには、基礎となるハードウェアの分岐命令に密接に基づいた条件付きgotoしかなかった。)Algol委員会のメンバーだったMcCarthyは、条件分岐をAlgolに導入し、そこからほとんどの他の言語に広がった。
2. 関数型。 Lispでは、関数は第一級オブジェクトである——それらは整数や文字列などのデータ型と同じで、リテラル表現を持ち、変数に格納でき、引数として渡すことができる、など。
3. 再帰。 再帰はLisp以前にも数学的概念として存在していたが、Lispはそれをサポートした最初のプログラミング言語だった。(関数を第一級オブジェクトにすることに暗に含まれているとも言える。)
4. 変数の新しい概念。 Lispでは、すべての変数は実質的にポインタである。型を持つのは値であり、変数ではない。変数の代入や束縛は、ポインタのコピーを意味し、それが指すもののコピーではない。
5. ガベージコレクション。
6. 式で構成されるプログラム。 Lispプログラムは式の木であり、それぞれが値を返す。(一部のLispでは、式が複数の値を返すこともある。)これは、式と文を区別するFortranとその後のほとんどの言語とは対照的である。
この区別がFortranにあったのは自然なことで、(入力形式がパンチカードだった言語で驚くことではないが)言語が行指向だったためである。文をネストすることはできなかった。そして、数学が動作するためには式が必要だったが、他の何かが値を返すようにすることには意味がなかった。なぜなら、それを待つ何かが存在し得なかったからである。
この制限はブロック構造化言語の登場で消えたが、その時にはもう手遅れだった。式と文の区別は定着していた。それはFortranからAlgolに広がり、そこから両方の子孫に広がった。
言語が完全に式で構成されている場合、どのようにでも式を組み合わせることができる。Arcの構文を使って、次のように言うことができる。
(if foo (= x 1) (= x 2))
または
(= x (if foo 1 2))
7. シンボル型。 シンボルは文字列とは異なり、ポインタを比較することで等価性をテストできる。
8. シンボルの木を使用したコードの表記法。
9. 言語全体が常に利用可能。 読み込み時、コンパイル時、実行時の間に本当の区別はない。読み込み中にコードをコンパイルまたは実行でき、コンパイル中にコードを読み込んだり実行したりでき、実行時にコードを読み込んだりコンパイルしたりできる。
読み込み時にコードを実行すると、ユーザーはLispの構文を再プログラムできる;コンパイル時にコードを実行すると、マクロの基礎となる;実行時にコンパイルすると、Emacsのようなプログラムでの拡張言語としてのLispの使用の基礎となる;そして実行時に読み込むと、プログラムはs式を使用して通信できる。これは最近XMLとして再発明されたアイデアである。
Lispが最初に発明されたとき、これらすべてのアイデアは、1950年代後半に利用可能だったハードウェアによって大きく支配されていた普通のプログラミング実践からは遠く離れていた。
時間が経つにつれて、一連の人気言語に具体化されたデフォルトの言語は、徐々にLispに向かって進化してきた。1-5は今や広まっている。6は主流になりつつある。Pythonには7の形式があるが、それに対する構文はないようだ。8(と9)はLispマクロを可能にするもので、これまでLispに独特のものだが、おそらく(a)それにはそれらの括弧、または同様に悪い何かが必要であり、(b)その最終的な力の増分を追加すると、新しい言語を発明したと主張することはできず、Lispの新しい方言を設計しただけになるからだろう;-)
今日のプログラマーにとって有用ではあるが、Lispを他の言語が採用したランダムな便宜からの変異という観点で説明するのは奇妙だ。おそらく、McCarthyはそう考えていなかっただろう。LispはFortranの間違いを修正するために設計されたのではなく、計算を公理化する試みの副産物として生まれた。