[ 目次, 前節, 次節, 索引 ]

4  超言語的抽象



... 魔法は言葉にある. ---アブラカダブラ, 開け胡麻, など--- しかしある物語の呪文は, 次の物語では呪文ではない. 真の魔法はどの呪文がいつ, 何のために働くかを理解することである. トリックはトリックを学ぶことである.
... そしてこれらの言葉は, アルファベットの文字で出来ている; ペンで書ける二十字余りの記号である. これが鍵だ. そこに手が届きさえすれば宝でもある. それは宝への鍵が宝であるようなものだ.

John Barth キメラ

プログラム設計の勉強で, 熟練プログラマは, 設計の複雑さをすべての複雑なシステムの設計者が使うのと同じ一般的技法を使って制御するのを見た. 基本要素を組み合せて合成オブジェクトを作り, 合成オブジェクトを抽象化して高水準の組立てブロックを作り, システム構造の適切で大規模な視点を採用し, 部品化力を保持する. これらの技法の例示に, 実世界の複雑な現象をモデル化するプロセスを記述したり, 計算オブジェクトとプロセスを構成したりする言語としてLispを使ってきた. しかし徐々に複雑な問題に立ち向うにつれ, Lispや他の固定したプログラム言語は目的に不十分なことが分ってくる. われわれの考えをより効果的に表すため, 絶えず新しい言語に変らなければならない. 新しい言語を創るのは工業設計で複雑さを制御する強力な戦略である: 手元の問題に特によく適合した, 基本演算, 組合せ手段, 抽象手段を用いて, 問題を異る方法で記述する(従って考える)ことが出来る新しい言語を採用し, 複雑な問題を扱う能力を拡大することが多い.1

   プログラミングには多くの言語が使われる. 特定の計算機の機械語のような, 物理的言語がある. こういう言語は記憶装置や基本的機械命令の個々のビットを使ったデータや制御を表現することに関係する. 機械語のプログラマは, 与えられたハードウェアを使い, 資源に制約された計算の効率よい実現のためのシステムや, ユーティリティを構成しようとする. 機械語の基盤の上に構成された高水準言語は, ビットの集りとしてのデータの表現や, 基本演算の列としてのプログラムの表現の考え方を押し隠す. これらの言語は, 手続き定義のような, システムの大規模構成に適した合成と抽象の手段を持っている.

   新しい言語を創設する 超言語的抽象(metalinguistic abstraction) は, 工学的設計のすべての分野で重要な役割を果す. これはプログラミングにおいて, 新しい言語が形式化出来るだけでなく, 評価器を構築してこれらの言語を実装し得るが故に, 特に計算機のプログラミングで重要である. プログラム言語の 評価器(evaluator)(または解釈系(interpreter))とは, その言語の式に作用させられると, その式を評価するのに必要な行動を実行する手続きのことである.

   これをプログラミングの最も基本的な考えと見るのは決して誇張ではない:

プログラム言語での式の意味を決定する評価器は, もう一つのプログラムに過ぎない.
この点を認めるのはプログラマとしてのわれわれ自身の見方を変えることである. われわれは他人の設計した言語の利用者であるよりは, 言語の設計者として自分を見るようになる.

   実際殆んどのプログラムは, ある言語の評価器と見ることが出来る. 例えば2.5.3節の多項式操作システムは, 多項式演算の規則を具体化し, それらをリスト構造のデータの演算を使って実装したものである. このシステムに, 多項式表現を読み込んだり, 印字したりする手続きを追加すれば, 記号演算の問題を扱う特殊目的の言語の中核が得られる. 3.3.4節のディジタル論理シミュレータや, 3.3.5節の制約伝播系は, それ自身, 独自の基本演算, 合成手段や抽象手段を持った正当な言語である. こういう見方をすると, 大規模計算システムに対処する技法は, 新しい計算機言語を構成する技法と一体になり, 計算機科学それ自身は, 適切な記述言語を構成する修練に過ぎ(ず, 不足もし) なくなる.

   では他の言語を使って言語を創設する技法への旅に出発しよう. 本章では, Lispを基盤として使い, 評価器をLispの手続きとして実装しよう. Lispは, その記号式を表現し操作する能力の故に, この作業に特に適している. その第一歩として, Lisp自身の評価器を構成することで, 言語がどう実装されているかを理解しよう. われわれの評価器で実装する言語は, 本書で使っているLispのScheme方言の部分集合である. この章で記述する評価器は, Lispの特定の方言で記述してあるが, 逐次型計算機のプログラムを書くために設計した式主体の言語の評価器の本質的な構造を含んでいる. (実際, 殆んどの言語処理系は, その根底に小さな「Lisp」評価器を持っている.) この説明と議論のため, 評価器は単純化され, 製品品質としてのLisp処理系には重要な機能の一部も取り除いてある. それにも拘らずこの単純な評価器は, 本書のプログラムの殆んどを実行するのに適している.2

   評価器をLispプログラムとして手が届くようにする重要な利点は, 評価器プログラムの修正として記述し, 別の評価規則が実装出来ることにある. この能力を巧みに使う一つの場所は, 3章の中心的論点であった計算モデルが, 時の観点を具体化するいろいろな方式の制御を試みる所である. そこでは状態と代入による複雑性を幾分緩和し, ストリームを使って実世界の時の表現を計算機内の時から分離した. しかしわれわれのストリームプログラムは, Schemeの作用的順序評価によって制約されているので,ある程度煩わしい. 4.2節では基底の言語を変更し, 評価器に正規順序評価 (normal-order evaluation)が出来るように修正することで, より優美な解決法が出来るようにする.

   4.3節は更に野心的な言語的変更を実装する. 式は唯一ではなく, 多くの値がとれるようにする. この非決定性計算(nondeterministic computing)の言語では, 式の可能な値すべてを生成し, 次にある制約を満す値を探すようなプロセスを表現するのが自然である. 計算と時のモデルを使えば, これは一組の「可能な未来」へ時間分岐し, 次に適切な時の流れを探すのに似ている. 非決定性評価器を使えば, 多値を記憶し, 探索を実行することは, 言語の基盤の機構で自動的に扱われる.

   4.4節では, 入出力を持つ計算としてよりは, 関係を使って知識を表現する論理型プログラミング(logic programming)言語を実装する. これは言語をLispや殆んどの通常の言語から劇的に違ったものにするが, 論理型プログラミング評価器はLisp評価器と本質的な構造を共有することが分る.


1 この考えは工学のすべてを通じて広まっている. 例えば電気工学者は回路記述に多くの異った言語を使う. それらの二つをあげれば, 電気的ネットワーク(network)の言語と電気的システム(system)の言語である. ネットワーク言語は離散的電気素子を使った部品の物理的モデル化を強調する. ネットワーク言語の基本オブジェクトは, 電圧と電流という物理的変数を使って特徴づけられる, 抵抗, キャパシタ, インダクタやトランジスタのような基本的電気部品である. ネットワーク言語で回路を記述する時, 技術者は設計の物理的特性に注目する. 対照的にシステム言語の基本オブジェクトはフィルタや増幅器のような信号処理部品である. 部品の関数的振舞いだけが重要で, 電圧や電流のような物理的実在に関心がなく, 信号だけを操作する. システム言語は, 信号処理システムの要素は電気的ネットワークで構成されているという意味で, ネットワーク言語の上に構成されている. ここではしかし, 関心は与えられた応用問題を解くための電気的部品の大規模な構成であって, 標準部品の物理的実現可能性は仮定されている. 言語のこういう階層的集成は, 2.2.4節の図形言語で示した成層設計技法のもう一つの実例である.

2 われわれの評価器が取り外したもっとも重要な機能はエラーの扱いと虫とり支援の機構である. 評価器の更に広範な議論については, Friedman, Wandおよび Haynes 1992参照のこと. そこにはSchemeで書いた一連の評価器を使って進行するプログラム言語群の説明がある.

[ 目次, 前節, 次節, 索引 ]