命令型プログラミングはどこに行くのか

2008年11月12日(水)
若槻 俊宏

命令型プログラミングパラダイムとは

 現在主流のプログラミング言語は、本質的にはハードウエアの実行メカニズムに深く根ざして発展してきた言語です。すなわち、固定長メモリセル列の上にデータ構造を構築し、状態を表現します。そして機械語命令列をプロセッサが順番に実行し、状態遷移を行うというチューリングマシン的メカニズムです。プログラミング言語が変われば、1つの命令文が扱えるデータ構造の粒度や抽象度も大きく変わりますが、「データ構造を構築し、計算を実行するためのアルゴリズム(命令文の列)を記述する」というパラダイムには変わりありません。

 本連載の視点では、PascalやCなどの構造化プログラミングや、C++やJavaのようなオブジェクト指向プログラミングなども、本質的には命令型パラダイムに含まれると考えます。

 命令型プログラミングは、次回紹介する「宣言型プログラミング」と対になる概念です。「手続き型プログラミング」という用語も、ほぼ同じ意味で使われますが、これはオブジェクト指向プログラミングなどとの対比として用いられることが多いため、本連載の趣旨とは少し離れてしまいます。

命令型パラダイムの歴史

 コンピュータが開発された当初は、非常に高価ものだったので、とても一般人が気軽に使えるようなものではありませんでした。また、性能が貧弱だったため、できることや動かし方も決まりきったものにならざるをえず、ソフトウエアはハードウエアのおまけのような扱いでした。そもそもプログラムという概念、すなわちストアドプログラム方式のコンピュータが生まれる前は、直接ハードウエアを変更することによって動作を変えており、ソフトウエアという概念自体が存在しませんでした。

 しかしその後、コンピュータは飛躍的に進歩し、応用分野も社会的重要性も加速度的に増加してきたというのは、ご存じの通りです。今では私たちの生活の隅々にまでコンピュータが浸透し、社会基盤を円滑に動かし、豊かな生活を送るために欠かせないものとなっています。

 それに伴い、ソフトウエアは、さまざまな問題ドメインを含む、大規模で複雑なものとなってきました。また、ハードウエアが急速に安価になり、かつてはおまけ扱いだったはずの、ソフトウエアを作るコストの方がはるかに高価になってきました。必然的に、ソフトウエア開発を楽にするための技術の重要性が増し、さまざまなプログラミング言語や開発環境、ミドルウエアやライブラリといったものが整備されるようになり、現在に至ります。

 命令型パラダイムの発展を一言で言うならば「記述の高級化(抽象化)と、プログラムのモジュール化(影響範囲の局所化)」と言えます。

 「高級」というのは、人間に近いという意味で、ハードウエアから離れる(ハードウエアを抽象化する)ほど高級と言えます。高級言語というのは、要するにアセンブリー言語以外のすべてのプログラミング言語のことです。高級言語の登場により「すべてをアセンブリー言語でベタに書く必要は無く、高級な記述から機械語を生成すれば良い」という画期的なパラダイムが誕生しました。これは今でこそ常識となっていますが、BNF記法などのコンパイラ技術が成熟するまでは、人工知能と同じような夢物語の一種だったのです。

 しかし、いくら記述が高級になったとしても、全体がスパゲティのように複雑に絡まっているプログラムでは、開発や保守が困難となります。構造化プログラミングは、プログラムの制御構造を整理し、一度に考えなければならない範囲を狭めることに成功しました。CLOSやSmalltalkではなく、C++のような意味でのオブジェクト指向プログラミングは、より積極的にこれを推し進めた、手続きとデータ構造のモジュール化を強力に支援するための枠組みと言えます(図1)。

 続いてプログラミング言語の汎用と専用について考えてみましょう。

汎用言語と専用言語

 現在のプログラミング言語のほとんどは、「汎用」プログラミング言語と呼ばれるものです。コンピュータの初期においては、軍事関係の数値計算や、企業向けの事務処理が用途の大半で、数値計算にはFORTRAN、事務処理にはCOBOLといったように、問題ごとに専用のプログラミング言語と定型的なノウハウが存在していました。

 しかし、現在のコンピュータシステムはさまざまな問題ドメインにまたがった複雑なものになっているため、1つの問題ドメインに特化した専用言語では、不得意な部分のプログラミングが困難となってしまいます。FORTRANやCOBOLなどの専用言語も、時代の要請に従って、Cなどとの他言語インタフェースやオブジェクト指向プログラミングのサポートなどを取り込み、汎用化、高機能化しています。

 成功し普及した言語は、さまざまな問題ドメインにおいて、多種多様なプログラマのニーズに応えなくてはいけないので、言語仕様が肥大化していく傾向にあります。そのような言語は多くのソフトウエア資産を抱えており、互換性を失うような言語仕様の変更は難しくなるため、機能の統廃合ではなく、追加という形を取らざるをえないためです。

 しかし、その中には特定の分野では必要不可欠なものの、安易に使用すると容易にバグの温床となってしまうような機能が含まれる場合もあります。また、後付けの機能は、往々にして既存の言語仕様との統合が不十分なため、誤解を生んだり、使いづらかったりする場合があります。

 さらに、言語仕様の良しあしとは別の現実的な問題として、言語仕様が肥大化、複雑化すると、言語処理系を作るのが難しくなるという問題もあります。言語処理系が複雑で巨大なプログラムとなれば、それ自体にバグが混入する可能性が増えますし、高度な機能を使用するプログラムは解析や最適化が難しくなります。

汎用言語と専用言語のジレンマ

 汎用言語は、特定の問題ドメインにのみ特化するわけにはいかないため、専用言語に比べると記述が煩雑になってしまったり、最適化なども劣ったものになってしまうという本質的な問題点があります。いまだにスーパーコンピュータの世界や金融系のインフラシステムなどでFORTRANやCOBOLが現役なのには、過去とのしがらみ以外にも合理的な理由があるのです。

 ここで、問題点を整理してみましょう(図2)。結局は、私たちはアプリケーションごとに、適した言語を選んで使い分けていかなければならない定めなのでしょうか?

 汎用言語と専用言語の間にはトレードオフが存在します。それぞれの問題ドメインごとに必要な機能は異なるので、すべての人が満足する言語を設計することは極めて難しく、ほとんど不可能なことにさえ思えます。それゆえに、現在のような、多種多様な目的を持って設計された言語が存在するのだとも考えられます。

 新しいプログラミング言語を習得したり、乗り換えたりすること自体は比較的容易かもしれません。趣味でたくさんの言語でプログラミングを楽しんでおられる方も多いと思います。しかし、仕事ともなれば、その言語の開発環境や言語処理系の成熟度、ライブラリやフレームワークの実績、プログラマの確保や教育など、それ以外にも検討しなければならないことが山ほど存在します。できることならば、言語は頻繁に変えたくないというのが人情ではないでしょうか。

 これらの問題の解決策として、昔からLispなどのコミュニティでは、汎用言語の中に、ユーザ定義で問題ドメインに特化した記法を作りこむDSL(Domain Specific Language)という手法が用いられてきました。次はこのDSLについて紹介しましょう。

ドメイン特化言語(DSL)

 DSLは、いきなり汎用言語でプログラムを書くのではなく、まずは汎用言語で専用言語を構築し、その専用言語でプログラムを書くという、ボトムアップな開発方法論です。

 Lispというプログラミング言語は、LISt Processingという名前が示す通り、リストでプログラムを記述するため、プログラム自体を簡単なリスト操作で変換できるという特徴があります。そのためLispのコミュニティでは、プログラムを直接書くのではなく、実行したいプログラムを生成するプログラムを書く、メタプログラミングという技法が多用されてきました。Lispはマクロという言語機能により、記法を自由に拡張することができるため、プログラム可能なプログラミング言語と呼ばれることもあります。

 例えば、Lispのマクロを使って、次回以降に触れるPrologというプログラミング言語の処理系をDSLとして実装すれば、Lispプログラムの中にProlog(のような Lisp)プログラムを直接記述することができますし、そのProlog的な記述の中ではLispの機能がすべて使えるのです。

 しかし、DSLも完全な解決策ではありません。Lispの高度なメタプログラミング技法についての優れた解説書である「on Lisp」において、著者のPaul Graham氏も図3のように言及しています。

 ここで一度原点に返ってみると、私たちが欲しいものは優れたプログラミング言語(機能)やプログラミングテクニックではなくて、コンピュータで問題解決するための一般的な方法論であることに気がつきます。

 DSLは、システム開発初期のプロトタイピングには最適かもしれませんが、そこから実運用に耐えるようなシステムの生成までをシームレスにつなげる枠組みに欠けています。例えばLispなどで書かれたプロトタイプは、最終的な製品となるまでには、C++やJavaなどの言語で書き直される場合が多いと考えられます。

 ここまでに紹介してきたプログラミングパラダイムは、すべて直接問題解決の方法(How To Solve)を人間が記述するというパラダイムでした。DSLも、より強力なHowをボトムアップで構築するための方法論と考えることができます。

より知的なプログラミングを目指して

 発想を転換しましょう。問題の解き方を人間がすべて記述するのではなく、代わりにコンピュータに考えてもらうことはできないのでしょうか。そんな魔法のようなことが可能なのでしょうか。もちろん、コンピュータが1からすべてを考えて解決してくれることは、本物の人工知能が完成しない限り不可能でしょうし、それはわれわれが今考えている数十年のスパンでは、おそらく不可能でしょう。

 そうではなく、必要最小限の記述から、自動的に問題解決のための方法をコンピュータが推論してくれるような枠組みです。その際に記述するものは、問題の解き方ではなく、問題の性質や満たすべき制約などの定義(What To Solve)です。これは、DSLや専用言語のように、ボトムアップで強力なHowを提供するための枠組みの対極です。トップダウンに与えたWhatからHowを演繹(えんえき)するのです。

 次回は、もうひとつの流れ、数理論理学的な理論に根ざして発展してきた宣言型プログラミングについて考えていきます。このパラダイムでは、後の等価変換型プログラミングにつながる、重要な概念が多数研究されました。

 なお、本稿の執筆にあたって、以下を参考にしました。

Paul Graham(著)野田 開(訳)『On Lisp―Advanced Techniques for Common Lisp』オーム社(発行年:2007)

北海道大学大学院
北海道大学大学院 情報科学研究科 博士後期課程(D1)。当初はAI研究に興味を持っていたのだが、現在のプログラミング技術の水準では不十分だと考え、いつの間にかプログラミングの基礎理論を研究する道に。大学院時代は、等価変換に基づく問題解決、特にルール型プログラムから命令型プログラムを合成するための理論について研究。2008年11月21日付けで、京都マイクロコンピュータ株式会社に入社予定。今後はデバッガ技術に基づきソフトウエアとハードウエアの本質を突き詰めて行くつもりである。http://alohakun.blog7.fc2.com/

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています