図1の下半分、点線より下の部分には、あまり有名でない言語が並んでいます。幾つかは名前くらい聞いたことがあるかもしれません。これらの言語は主にアカデミックな領域(大学や企業の研究機関など)で使われることが多く、図1の上半分に登場する言語ほど、たくさんのユーザーを獲得することはありませんでした。しかし、学術分野で研究し使われてきた言語の中には、強力な機能を持つものがたくさんありました。実は「プログラミング言語の新潮流」とは、これら「知られざる言語」たちの機能がメインストリームの言語に取り込まれているという流れなのです。Part 1ではそれらの言語の幾つかを紹介してみようと思います。
Lispのことを知られざる言語などと呼んでしまうと、怒り出す人もいるかもしれません。LispはFortranに続くくらい古い言語であり、また人工知能をはじめとする、さまざまな研究分野で非常に広く活用されてきました。趣味のプログラミングや商業プログラムの領域ではそれほど有名ではありませんが、それでもEmacsやAutoCADのカスタマイズ言語として、あるいは「クラッシュ・バンデクー」のゲーム記述言語などとして、Lisp系言語はいろいろなところで密かに活躍しています。Lispの簡単なサンプルプログラムをリスト1に示します。
(defun fact (n)
(if (= n 0)
1
(* n (fact (1- n)))))
古典的言語の代表格であるFortranが、正直なところ古臭い印象を与えてしまうのに対して、ほぼ同じくらい古いはずのLispにはそのような印象がありません。むしろ、見かけは変わっているものの、つぎつぎと新しいアイデアを生み出しています。プログラミング言語の新潮流と見なされる新しい概念の多くも、実はずっと昔にLispで発明されたものが多いのです。
Lispは、1958年にMITのジョン・マッカーシー(John McCarthy)によって「発見」されました。当初、Lispはアルゴリズムの表現方法として考え出されたものです。Fortranをはじめとするほかのプログラミング言語が、あくまでもコンピュータに処理手順を伝達するための記法として誕生したのに対して、Lispは数学的記法をコンピュータで実行可能にしたという違いがあります。FortranとLispの最大の違いは、このような誕生のいきさつにあると言えるでしょう。
Lispには、次のような非常にユニークな特徴が備わっていました。
これらの特徴は、要するに現代で言うリフレクション機能を備えていることを意味しています。これによってLispは、目的に合わせて言語自身をどんどん拡張できる柔軟性を備えていました。学術分野ではこのような性質が非常に好ましかったので、Lispはアカデミックな領域で広く使われ、人工知能などのいろいろな研究分野で活用されたのです。
しかし、あちこちの大学や研究所でLispが使われるようになって、だんだん困った事態も発生してきました。すでに述べたように、Lispはコアがシンプルで簡単に実装できる上、言語拡張も簡単です。そのため、あちこちにLispの方言が生まれてしまって、「せっかく開発したLispプログラムが、よそのLisp処理系では動かない」という事態が頻発するようになったのです。
これを受けて2つの動きが生まれました。1つは、世の中に存在するあらゆるLispの最小公倍数的な存在を目指したCommon Lispです。実際には、互いに矛盾する部分の解消があったり、既存のものとはまったく違う新しいアイデアを盛り込んだりしたので、厳密には最小公倍数ではないのですが、とにかく古今東西のあらゆるLispプログラムを移植するのに必要そうな機能を盛り込んだ巨大なLisp仕様です。Common Lispは最終的に、ANSI規格として策定されています。
もう1つの動きは、長い歴史の中でLispが抱え込んできたいろいろなものをすべてそぎ落として、限りなくシンプルで切れ味の鋭いLisp言語を定義しようというものです。このLispはSchemeと呼ばれました。現在Lispと言えば、そのほとんどがCommon LispかSchemeのいずれかを意味します*。
後述しますが、Lispから生まれた概念はたくさんあります。それはLispが、長年その柔軟性によって「言語機能の実験場」としての役割を果たしてきたことと、学術分野の頭のいい人たちが、研究成果として、あるいは自分たちがラクをするために精進してきたことの結果です。
Smalltalkは、1970年代にダイナブック構想を実現させるためのプログラミング言語として開発が始まりました。ダイナブック構想とは、アラン・ケイ(Alan Kay)らが計画した「子供たちにコンピューティングパワーを」というプロジェクトです。初期のSmalltalkはBASICで書かれた小さなプログラムとして始まったそうですが、最終的にはLispの影響を強く受けた*言語になりました。アラン・ケイは、「子供たちから離れてしまった」と不満を覚えていたそうですが。
Smalltalkはオブジェクト指向という考え方を世に広めた言語としても知られています。子供たちがプログラムの構造を理解しやすくするために導入された考え方ですが、その後多くの言語に影響を与え、現在ではオブジェクト指向機能を持たない言語の方が少数派になってしまいました。
しかし、オブジェクト指向という概念そのものは、Smalltalkによって発明されたものではありません。その概念は、1960年代後半スウェーデンのクリステン・ニガルド(Kristen Nygaard)らによってSimula言語に導入されたものです。当時は「オブジェクト指向」という単語はまだありませんでしたが、クラスや継承などオブジェクト指向プログラミングにとって重要なアイデアはSimulaにおいてすでに実現されていました。
ビアルネ・ストラウストラップ(Bjarne Stroustrup)によるC++は、オブジェクト指向という考えをSmalltalk経由ではなく、Simulaから直接導入しています。以前お会いしたときに直接聞いたところによると、ストラウストラップは大学院時代にSimulaのユーザーであったため、その機能をC言語に取り込みたかったというのが、C++の直接の開発動機だったそうです。
ML(Meta Language)はLispほど有名ではない言語です。もともとはEdinburgh大学のロビン・ミルナー(Robin Milner)らによって開発されたEdinburgh LCF(Logic for Computable Function)定理証明システムの推論規則を記述する言語として設計されました。MLは関数をベースにしたプログラミング言語なので、関数型プログラミング言語と呼ばれます。MLの簡単なサンプルプログラムをリスト2に示します。
fun fact 0 = 1
| fact n = n * fact(n-1);
MLは最古の関数型プログラミング言語ではありませんし、最高の関数型プログラミング言語でもありません。最古の関数型プログラミング言語は、(おそらく)ジョン・バッカス(John Backus)*が作ったFPでしょうし、また長らくLispも関数型プログラミング言語*と呼ばれてきました。しかし、「数学的な関数を意識したプログラミング言語」のうち、最も早く実用レベルに到達したのがMLであることは間違いないでしょう。一方、後で紹介するHaskellなどと異なり、MLは副作用を完全に排除していないので「純粋でない」関数型言語と呼ばれることもあります。
MLの最大の特徴は、やはりその型システムでしょう。MLはすべての変数や式が厳密な型を持つ静的型の言語です。しかし、型推論システムが組み込まれているので、ユーザーはほとんど型を明示的に指定する必要がありません。例えばリスト2のプログラムでは、「factという関数は整数を引数に取り、整数を返す」と型推論システムが自動的に判定してくれています。また、関数実行時にパターンマッチが発生するのも特徴です。リスト2では「0のとき、〜。それ以外のとき、〜」という形で、引数のパターンによって実行される定義を切り替えています。
MLの処理系としては、SML/NJやOCamlが有名です。
Haskellは純粋関数型言語です。この場合の「純粋」とは、副作用がないことを意味します。つまり、同じ引数を渡した関数はいつも同じ値を返し、状態の変更を引き起こす代入も存在しません。このことを「参照透過性」と呼びます。また、Haskellは「遅延評価」が基本です。つまり、値の計算は必要になったときにはじめて行われます。
Haskellのこれらの性質は、参照透過性のおかげで暗黙の状態がないことから、保守性が高く、また遅延評価のおかげで不必要な計算を避けることができ、無限列を簡単に取り扱うことができます。ただ、純粋関数型言語であるHaskellは、メインストリームの言語とはかなりかけ離れているので、身に着けるのが少々大変というデメリットもあります。
アプリケーション組み込みの分野では、Common LispにもSchemeにも属さないLisp系の言語(例えばEmacs Lispなど)もかなり生き残っている。
Smalltalk-80は、言語仕様はともかく内部的にはほとんどLispと同様であったという話もある。実際、実行モデルのレベルで両言語はかなり似ているし、実装に使われるテクニックもかなり共通している。
Fortranを設計した人。
初期のLispではあらゆるものに関数という名前がついていたので、しばしば関数型言語と呼ばれた。しかし、同じ引数を与えても異なる値を返すことがあったり、副作用(関数呼び出しがグローバルな状態を変更すること)があったりと、数学的な意味での「関数」型プログラミング言語ではない。
本記事は、オープンソースマガジン2006年10月号「プログラミング言語の進化を追え」を再構成したものです。
Copyright © ITmedia, Inc. All Rights Reserved.