プログラミング談義

今日大学で海外から研究室に来ている研究員の方とお話しする機会があった。最初は学術的な話ではなく単なる雑談だったのだが、雑談の内容が一転して研究員の研究分野の話になった。
話していた内容はプログラミングの事。特に日本でのプログラミング教育はどのように行われているのか、自分がプログラミングを勉強したときはどのように勉強して行ったのかといった事だった。
そして、自分がプログラミングをするときにはどのように考えながら行うかという話になったとき、急に研究員の顔色が変わった。その研究員の研究内容は「プログラミングにおける知覚認識」だったのだ。
自分が話した内容はこうだ。
自分がプログラミングをするときには「中間言語」のようなものを使う。以下中間言語といったときは、自分の中での中間言語を指す。
中間言語自然言語とコンピューター言語の間にある道具である。中間言語の中の一番細かい要素は「シーケンス」「条件分岐」「ループ」である。もう少し細かくする事もできるが、後からコンピューター言語に翻訳するときにここまで出分解をやめておいたほうが都合が良いので、ここまでとしておく。これをプリミティブと呼ぶ事にする。
プリミティブは(関数型は除く)殆どのコンピューター言語に翻訳する事ができる。C・C++JavaC#PerlPHPPythonRubyあたりの主要な言語なら、プリミティブから翻訳する事ができると思う。
中間言語の一番の特徴はは「入れ子」になっている点である。あるアルゴリズムは別の複数のアルゴリズムからなるというのと、あるアルゴリズムは複数のプリミティブからなる、という考え方である。仮に新しいアルゴリズムを覚えるときは、アルゴリズムの手続き、入出力インタフェース、その効果を覚え、他のアルゴリズムとの入れ子として使えるようにしておく。
プログラムを書くときはコンピューターにやらせたい事をトップダウン中間言語に展開していき、最終的にプリミティブに分解してからコンピューター言語として書いていく。展開の仕方は経験と勉強から知識として覚えているものを使う。例えば深さ優先探索アルゴリズムならこんな感じで展開していく。

深さ優先探索

深さ優先探索」を展開して、

スタックが空になるまでループ
	スタックから要素をポップする
	要素を展開してスタックに入れる

「全ての要素を探索するまでループ」を展開して、

while (!stack.isEmpty()){
	スタックから要素をポップする
	要素を展開してスタックに入れる
}

「スタックから要素をポップする」を展開して、

while (!stack.isEmpty()){
	STATE state = stack.pop();
	要素を展開してスタックに入れる
}

「要素を展開してスタックに入れる」を展開して、

while (!stack.isEmpty()){
	STATE state = stack.pop();
	要素を展開し終えるまでループ
		展開した要素をスタックに入れる
}

「要素を展開し終えるまでループ」を展開して、

while (!stack.isEmpty()){
	STATE state = stack.pop();
	for (int expansionIndex = 0; expansionIndex < numberOfexpansion; ++expansionIndex){
		展開してスタックに入れる
	}
}

「展開してスタックに入れる」を展開して

while (!stack.isEmpty()){
	STATE state = stack.pop();
	for (int expansionIndex = 0; expansionIndex < numberOfexpansion; ++expansionIndex){
		要素を展開する
		展開した要素をスタックに入れる。
	}
}

「要素を展開する」を展開して、

while (!stack.isEmpty()){
	STATE state = stack.pop();
	for (int expansionIndex = 0; expansionIndex < numberOfexpansion; ++expansionIndex){
		STATE nextState = state.expand(expansionIndex);
		展開した要素をスタックに入れる
	}
}

「展開した要素をスタックに入れる」を展開して、

while (!stack.isEmpty()){
	STATE state = stack.pop();
	for (int expansionIndex = 0; expansionIndex < state.getNumberOfexpansion; ++expansionIndex){
		STATE nextState = state.expand(expansionIndex);
		stack.push(nextState);
	}
}

と、こんな感じである。別の言い方をすると、プログラムの部品をパーツごとに作り、それらを木構造でつなぎ合わせるということもできる。
ここまで研究員の方に話して、その研究員の方はものすごく興奮していた。何と言うか「その発想は無かったわ」といった感じだ。
この考え方はプログラミングに慣れている人であれば、ある程度の人が無意識にやっている事だろ思う。また、展開するという考え方はオブジェクト指向カプセル化とも関連してくると思う。特に不自然な考え方ではないはずだ。
問題点を挙げるとするならば、この考え方では関数型言語を記述する事ができないという点だ。また再帰との相性も余り良くない気がする。
今度その研究員に会うときは、この記事を英訳しながら見せようと思う。