いものやま。

雑多な知識の寄せ集め

「Lucid, the Dataflow Programming Language」を翻訳してみた。(その5)

前回の続き。

1.6 Honest, Folks, We Was Just Funnin’

この数ページで、プログラミング言語に取り組んでいるほぼすべてのコンピュータ科学者を致命的に怒らせただろう。
今や、怒れるカウボーイ達、ウィザード達、伝道師達、技術者達、よろず屋達(Handymen、修正主義者達のこと)のリンチ暴動が集まっている。
彼らは瞬間的に紛争を忘れ、私たちを通りの向こうにある古い狩猟用の木に引きずり出すという決意に結束している。

読者はおそらく私たちほとんど同情していないだろう。
結局のところ、ソフトウェア危機を解決しようとするほとんどすべての試みを無駄に却下しただけではないか?
真面目な研究者を半狂乱なマンガのキャラクターとして描写して、傷害に侮辱を加えていなかったか?

実際には、私たちの風刺は、ターゲットに見えるかもしれない少数の人々にしか向けられてない。
例えば、プログラムの検証や意味論を扱うほとんどの人は、かなり賢明である。
彼らは、自分の研究が重要だと考えているが、既存の言語の新しい意味論による記述がソフトウェア危機を解決しようとしているという幻想のもとにはいない。
彼らは実際にウィザードと呼ばれるに値するほどではない。

同じように、ほとんどが単なる死人であるような人々によってプログラムが構築されることを、ほとんどのプログラマ・ソフトウェアエンジニアはよく知っている。
彼らは、専門的な機械に近いプログラミングが、ソフトウェア開発の問題に対する普遍的な救済策ではないことを知っている。
賢い人でさえ、あまりにも多くの巧みさが殺すことができることを知っている。
これらの人々は真のカウボーイではない。

同様に、ほとんどの技術者達は、良い環境が悪い言語に対する救済策ではないことを知っている。
多くの伝道師達は、良い方法論では本当に悪いシステムを克服できないことを知っている。

私たちの批判は、彼らが取り組んでいる特定の問題がソフトウェア危機の根底にあると確信している、小規模少数派に対してのものである。
たとえば真のウィザードは、正式なツールがないことが命令型言語の問題のすべての原因になっていると確信している。
同じように、実際の技術者は、現実の問題は適切なプログラミング環境がないことであると確信している。

彼らは解決策を持っていると確信しているが、みな間違っている。
彼らは、使用されているマシンの基本設計に問題があるとしていないため、間違っている。
代わりに、彼らは問題がマシンの使用方法にあると考えている。
彼らは問題を技術的なものとして見ていない。
多くのアプローチは非常に異なり、あまり共通性がないが、1つ共通な点がある。
すなわち、彼らはソフトによる解決(ソフトウェア、数学、方法論など)をハードの問題に提案している。

ある研究者グループは、私たちのブラックリストからはっきりと抜け落ちている。
私たちは、新しい種類のマシンを設計する人々については、何も悪いことを言っていない。
もちろん、私たちは彼らを、はんだこてでソフトウェアの危機を解決することができると思っている狂信者、修理士と風刺することも出来た。
結局のところ、彼らは、カウボーイや伝道師と同じように、彼らの仕事が将来の鍵であると確信している。

違いは、彼らは正しいということだ。
ソフトウェア危機全体の根底にある問題は、実際にはマシンアーキテクチャの問題である。
私たちは提案された個々の新しいアーキテクチャがその仕事に縛られなければならないと言っているわけではない。
しかし、全体としては、ハードウェアの研究者が解決策につながる唯一の道に従っている。
主題の半分である「ソフト」のコンピュータ科学者(意味論者、方法論者、言語設計者)には、選択肢がある。

一つは、彼らは自分のスキルとエネルギーを、古い逐次型・命令型アプローチを少しでも長くしてみようと努力することに専心することが出来る。
この選択をするのは、カウボーイ、ウィザード、伝道師、技術者、よろず屋である。

もう1つの選択肢は、新しいマシンや計算形式の模索を試みることである。
この選択は、新しい世代のコンピュータに適した新しい種類の意味論、方法論、言語などを発見するのに、技術とエネルギーを捧げることを意味している。
この道を歩む人たちは未来を選んでおり、彼らの努力が無益でもばかげてもいないことが示されるだろう。

もちろん、第3の可能性もある。
それは、問題は無視して、特定の計算形式からは独立した意味論、方法論、検証システムなどを開発しようとすることである。
これは可能であり、命令型言語の検証は、非手続き型言語にも容易に適用できる。
しかしながら、研究者は問題を永遠に避けることは出来ない。
そのような、立場を明らかにしていないと自身では思っている人々は、(計算が本質的に逐次的であるという確信など)無意識の偏見の犠牲者であることが多い。
生涯の仕事としている主題のリスクについての、根本的な論争を避けようとする研究者は、無関係であることを最後に証明する。

1.7 非手続き型言語

命令型のプログラマや言語設計者が、マシンとの愛憎関係を持つことは明らかである。
一方では、彼らはマシンから離れたがり、抽象的で高レベルで構造化されていて数学的で問題指向でありたいと思っている。
同時に、彼らはマシンに近づき、計算の詳細を制御し、プログラムをできるだけ効率的にするという圧倒的な衝動を持っている。
もちろん、プログラマがマシンに近づくことを可能にする機能と修繕は、すべてのトラブルを引き起こすものである。
これらは、未熟者が悲しみ、ウィザードが分析に困り、伝道師は悪と告発し、よろず屋は永遠に修復している機能である。

命令型言語の問題は、多くの人々にマシンとの関係の「愛」の側面を再考させている。
彼らは、プログラミング言語の最も基本的な原則、すなわち計算や動的な活動を指定することが意図されているため、本質的に動的であるということを拒否しようとしている。

PASCALのような言語の本質的に動的な2つの機能は、代入と制御フローである。
当然のことながら、多くの人がそれらを排除しないべきかのか、疑問に思った。
この急進的な解決策は、最も重い制御フロー、すなわち、goto文が不名誉に引退することを余儀なくされた後、信頼性を得た。

代入も制御フローも、本当には必須ではないことは古くから知られており、純粋に静的で数学的な言語でプログラムを書くことは可能である。
約50年前、チャーチは計算可能な数値関数を(関数を定義するための非常に簡単な形式である)ラムダ計算で表現できることを示した。
後でクリーネ(Kleene)は、同じことが、再帰的な関数定義である「構造」だけの単純な言語でも言えることを示した。
発明された最初の高レベル言語の1つはLISPであり、その「純粋なコア」には代入も制御フローもなく、確かにLISPはチャーチとクリーネの仕事の一部に基づいていた。

手続き型言語(すなわち、代入や制御フローのない言語)は、多くの点で命令型言語よりはるかに優れているという一般的な合意がある。
手続き型言語は、参照透過(referentially transparent)であり、プログラムに現れる式の値は、部分式の値だけに依存し、これらの部分式が評価される順序には依存しない。
特に、関数(または「関数手続き」)は、実際には単語の通常の意味での関数を表している。
関数によって返される値は引数の値によって決定され、関数が「呼び出される」「時間」から独立している。
つまり、数学記号(+など)は、従来の数学とまったく同じように使用される。
非手続き型プログラマによって使用される表記法は、プログラマによって使用のために修正された、従来の数学の表記法である。

ウィザード達はもちろん、非手続き型言語を喜んで受け入れている。
なぜなら、従来の数学の手法を使用してプログラムを推論することができるからである。
非数学的な表記の数学的な意味を作るために全く新しい形式を開発する必要がない。
たとえば、等式の置換の法則が成り立つ。
すなわち、関数 f(x, y) x - 2 * yという式で定義されている場合、 f(A, B)という式は A - 2 * Bに置き換えることが出来る。
(少なくとも本書で考慮されている)非手続き型言語の意味論は、非常に簡単に仕様化することが出来る。
式の意味は、指定された関数または演算を部分式の意味に適用した結果であり、再帰的定義の意味はその最小不動点(least fixed point)である。

伝道師達もまた、恍惚としている。
ISWIMのような言語ではgoto文はなく、forループすらない。
副作用もなく、例えば式 f(x) - f(x)の値は、整数を含むとして、計算が終わるのならば、常に0である。
参照透過性は明らかにトップダウンアプローチをより簡単にし、関数定義とwhere節は優れた構造化ツールとなっている。

それにもかかわらず、非手続き型言語は、常に(特にカウボーイ達によって)、致命的な欠陥があるとみなされてきたーーすなわち、それらは(おそらく)本来的に非効率的である、と。
この(非難された)非効率性の根本的な原因は、反復の欠如である。
手続き型言語は純粋に定義的なものなので、変数の値は、少なくとも定義が有効なプログラムの範囲内では変更できない。
ダイクストラDijkstra、1965、p.215)は、以下のように言っている:

その優雅さにもかかわらず、深刻な反論がそのようなプログラミング言語(代入や制御フローがないもの)にはされるだろう。
スタック内の情報は、入れ子にされた存続時間を持つオブジェクトとして表示され、そして、その存続期間全体にわたって一定の値であるだろう。
そして、既存の名前付きオブジェクトの値は、別の値で置き換えられる。
結果として、新しく形成された結果を格納する唯一の方法は、スタック上に置くことであるが、スタック上に置かれた値を知るすべはなく、興味がないにも関わらず、スタック上の値の寿命は長くなる。
まとめると、それはエレガントだが不十分である。

※(訳注)おそらく、ループを再帰で実現することについて言及していて、その場合、スタックが深く掘られていくことになるが、その古い値は(ループでは)もう不要になっていて、しかも現在の関数から参照することも出来ないにも関わらず、ずっと生き続けてしまうということを指摘している。
なお、末尾再帰であれば(処理系の実装が賢ければ)そのようにスタックが掘られることはないが、その場合、メモリ上の値の置き換えは発生している。
(末尾再帰は、本質的にはループで必要なスタックを引数として表現し、gotoによるラベルジャンプでループを実現しているのと同じ)

ダイクストラの判断は、より古い従来の非手続き型言語(主にLISP)の経験によって確かに確認された。
多くのアプリケーションでは、LISPはきわめて適しているが、他の人にとっては、特に懐古的であるため、LISPによる解決は許容できないほど遅い。
実際、LISPの開発者は、性能を向上させるが参照透明性を破壊するいくつかの「不純な」機能(実際の反復のためのプログラムを含む)をすぐに追加した。

しかし、最近、研究者は非効率性の問題に対する可能な解決策を発見した。
ダイクストラによって強調された弱点は本質的な弱点ではなく、特定の種類の非手続き型言語を実装する特定の方法の弱点である。
ダイクストラの批判には、暗黙のうちに2つの仮定がある。
最初の前提は、プログラムが従来のALGOLランタイムスタックアプローチを使用してフォン・ノイマン・マシンで実行されることである。
2番目の前提は、基本データオブジェクト(関数の引数)が有限集合であり、スタックに積み上げられる「マシン・ワード」の集合であるということである。
関数の引数が無限のオブジェクト(例えば、すべての素数のリスト)であることを可能にする新しい非手続き言語が登場している。
これらの新しい言語は依然として立派であり、数学的であるーー数学者は何百年もの間、無限オブジェクトを扱ってきている。
それにもかかわらず、新しい言語は新しいプログラミングスタイル、(リダクションマシン、遅延評価、データフローといった)新しい実装方法を許可し、ダイクストラによって言及された、反復を再帰とする問題を避け、一つのプログラムで多くのプロセッサが評価の協力を行える。
手続き型言語は、ある日、効率性と優雅さにおいてFORTRANと競合するかもしれない。

反復の代わりに再帰的定義のみを使用して、効率的にプログラムすることは可能かもしれない。
しかし、この奨励的な開発により、一部は完全に反復を放棄するようになった。
彼らは非手続き型言語が反復を持つことができないということを無神論的に受け入れている。
実際、非手続き型プログラミングは本質的に操作や動的な考慮事項から独立していると、彼らは原則をより一般的に拡張している。
彼らは、この「ダイナミズム」の欠如がプラスの美徳であると考えている。
彼らは、動的・操作の考えがプログラミング言語のすべての問題の源泉であると思っている。
プログラミングに対するこの神秘的で先見的なアプローチは、私たちが「丘の上のばか」と呼んでいるものを表している。
すなわち、プログラマは、単なる計算のやり方の詳細について言語と心に負担をかけてはならず、代わりに、静的で永遠な数学的対象について考えて、ただ計算の喧騒から離れて、丘の上に座っていなければならない、と。
もちろん、プログラムは実装されて、さらに効率的である必要があるが、(「神秘主義者達」によれば)それはエンジニアの、言い換えれば単なる商人の、関心事である。
プログラマは、この見解によれば、プログラムがどのように実行されるべきかについて何も知る必要はなく、数学的な観点からだけ理解するべきである、と。

神秘主義者達は、現在の「関数型プログラミング(functional programming)」コミュニティで特に強く象徴されている。
1つの特に極端な宗派は、関数はクリーンで高レベルであり、プログラマーの注目に値するが、その引数(卑しいデータオブジェクト)は汚れていて、低レベルであり、避けられるべきだと信じている。
ただのデータオブジェクトは、この宗派の支持者にとって、言い表せないほどありふれたものであり、彼らはそれを話すことさえ失望させると考えている。
したがって、その言語にはこれらのオブジェクトに名前がなく、変数と式は関数のみを表すことが出来る。
いくつかのデータフロー言語もこのカテゴリにいる。
これらの言語では、データフローは純粋に実装手法であり、非手続き型プログラマの洗練された感性を害するだけの操作概念である。

この理念に対する支持者は、実際の(「純粋な」)数学は本質的に静的オブジェクトを扱い、変化と動的活動は数学的精神とは異なるということを自明として、自身らを正当化している。
クリストファー・ストレイチー(Christopher Strachey)(1971、p.77)は、かつて次のように言っている:

...プログラミングにおける命令(またはコマンド)の使用は、変数を導入し、数学は一般に、この意味での変数の存在ーーすなわち、ある期間にわたって変化する値ーーを認識しない。
従来、数学は静的な状況だけを扱っている。
 オブジェクトの極限へのアプローチに関係する計算でさえ、一連の固定値の観点から対象を扱う。
 ...一方、プログラミングでは、プロセスの性質上、時間によって変化する変数を扱う。
プログラムは本質的に変更のスケジュールである。

(ストレイチーは、偶然にも、神秘的な視点を擁護していなく、むしろ、彼は代入文の理解に必要な新しい動的な数学を開発するウィザードを奨励していた)

しかし、数学が本質的に静的だというのは本当に正しいのだろうか?
数学者が時間とともに変化する値を決して扱っていなかったというのは本当に正しいのだろうか?
真実と違うことがあってはならない!
微積分が最初に開発されたとき、それはまさに操作の基礎にあった。
ニュートンは、時間と共に変化する流入量を導入した。
のちに、当然のことながら、微積分は、極限(または、より最近では、無限小という概念)の概念を用いて形式化された。
それにもかかわらず、微積分は本質的に量の変化、実際は滑らかに変化する量の研究である。
数学の基本原則は常に、量の概念を継続的に一般化することによって、静的な方法で動的を研究することだった。
例えば、昔「持ち去り」という動的だった概念は、負の数で公式化され、同じように「区分け」は有理数を使って形式化された。
数学は、常に様々な形の変化を研究してきている。

物理学者とエンジニアが、「極限への物体のアプローチ」に関連して、ストレイチーの計算の定義を受け入れるのは、非常に困難である。
実際に微分方程式を使用する人は、通常、速度、加速度、密度などのまさに操作上の概念を使用する。
動的な思考が「低レベル」であるとか、または混乱を生み出すということは、彼らには決して起こらない。
動的視点と静的視点との間に真の矛盾は見られない。
代わりに、彼らは反対であるが補完的で調和のとれた2つのアプローチを見ている。
数学が動的な状況をモデリングしている(または指し示している)とき、動的に考えないことがあるだろうか?
そうしないのは、なんとも愚かである!

神秘主義者達は基本的な問題(フォン・ノイマンアーキテクチャの不適当性)を認めているが、それを無視して問題を解決したいと思っている。
神秘主義者達は、彼らのプログラムがどのように実行されているか知りたくないし、少なくとも、プログラマが知るべきではないと思っている。
彼らの言語の意味論は、操作の考えを参照することなく与えることが出来るので、問題全体を自身の手で洗うことが出来ると考えている。
彼らはエンジニアに「ここに言語の意味論があり、それを実装し、望む関数を使用することが出来るので、フォン・ノイマンアーキテクチャに縛られてはならない」と言う。
神秘主義者達は、言語の設計はマシンに完全に依存しないと考えている!


ということで、本質的にはマシン・アーキテクチャの問題だ、というのが、筆者たちの主張。
フォン・ノイマンアーキテクチャに代わってデータフロー・アーキテクチャを考え、その上で動くプログラムを表現するためのプログラミング言語を考え、その数学的な意味論を、履歴を持った変数・関数で構成しようとしている、といった感じか。

それにしても、長い(^^;
興味深い議論ではあるんだけどね。
次でやっと1章が終わる予定。

今日はここまで!