Mindのしくみと特徴 



 Mindのプログラムは日本語の文章のようになっており、従来の言語に見られたような、奇妙な記号とか暗号めいた表現はない。あっけないほど単純なために、あまりプログラムらしくないと思われることだろう。
 Mindのプログラムは日本語の単語(機能や動作を表現する単位)の集まりである。たとえば、「ベルを鳴らす」という単語がある。これは文字通りベルを鳴らす機能であるが、この機能を利用するときどうやって記述するかというと、
ベルを鳴らす
のように、単にその単語名を書くだけである。他の言語でいうところの関数とかサブルーチンの呼び出しに相当するが、決して、
CALL ベルを鳴らす
あるいは、
ベルを鳴らす();
というような表現にはならない。
複数の機能を続けて利用したい場合には、
画面クリアし 二秒待ち ベルを鳴らす
というように、これもきわめて単純な表記となる(分かち書きであることに注目)。
 もっとたくさんの単語をならべても構わない。行が一杯になったら次の行に書けばよい。このあたりは本当に文章を書いている感覚に近い。

 データの扱いについては、例えば
「こんにちは。」を 表示する
というプログラムを実行すると、画面または出力先に次のように文字列が表示される。
こんにちは。
 上記のプログラムは、BASIC 言語であれば、
PRINT ”こんにちは。”
 また、C 言語であれば、
printf(”こんにちは。”);
といったところであるが、Mind では語順(目的語と動詞の関係)が日本語として正しい順になっていることに注目して欲しい。

 ここまで読まれた方は、「つまり、日本語に合わせるために、引き数と関数名を逆にしているんだね」と早合点されるかも知れないので、2つの点を補足しておきたい。
 1つには、一般的な多くの言語が持つ「動詞+目的語」という文法をベースにして、これを逆にしたのではなく、Mind の根本的なアーキテクチャが日本語そのものであり、何かを逆にしたという発想ではないという点である(注1)。
注1
Mind はFORTH というプログラム言語の原理を応用している。FORTH はアメリカ生まれでありながら、文法が日本語に似ている。
 もう1つは、一見、語順の問題にしか見えないものが、実はもっと大きな違いを含んでいるという点である。語順、すなわち記述の順番は、違いのほんの一部が見えているにすぎない。
 後者について次の記述をご覧いただきたい。
「こんにちは。」を 画面クリアしてから 表示する
 このプログラムでは、語順が違うだけでなく、途中に無関係な単語が挿入されている。しかし、これで正しく動作する。また、表現としてもそんなに不自然ではなく、普通の日本語として通用する。
 では、次はどうだろう。
画面クリアしてから 表示する
 上記では、何を表示するか(表示すべきデータ)が記述されていない。しかし、これでも日本語としての意味を理解することはできる。そう。これは、「何か」を(画面をクリアしてから)表示することを表しており、これもまたMind の正しいプログラムである。
 同様に、
2を  掛ける
という記述は、「何か」に2 を掛けるという処理を表しており、Mind の正しいプログラムである。

 以上のことから、Mind あるいは自然言語としての日本語を英語などと比べた場合、単に目的語と動詞が逆転している、といったような、品詞の並びの問題ではなく、もっと深いところの原理が違うらしいことがわかる。


 
 
スタックとは
 
 

 さて、Mind では、ユーザーが新しい単語を簡単に定義できるようになっている。たとえば次のように記述する。
二倍とは 2を 掛けることである。
 この表現で、「2を 掛ける」には、掛けるべき数値が1つ足りないにもかかわらず、そんなに不自然でないと思われるだろう。日本人は、このような表記を見たときに「暗黙のデータ」の存在を推察でき、「何かに2を掛けるのだろう」と解釈するからである。この暗黙のデータの格納場所を「スタック」と呼ぶことにする。
 スタックはMindの最も根源的なもので、Mindのプログラムはこのスタックという仕掛けの元で動くようになっている。
 スタックとはデータの格納場所で、一般的にコンピュータやプログラムで「スタック」というものと同じだが、Mindでは特にスタックの存在や、その中に入っているデータやその順序を意識する。
 次のようなイメージを浮かべて欲しい。

 上図で水平に伸びているのがデータを置く台である。左側に垂直になっているのは、この台の隅を示す。この隅の近くに最初のデータを置き、以下、右側に向かってデータを並べていく。データをスタックから取り出す場合には、この逆の順序、つまり、一番右側に置かれているデータから順に取り出すものとする。

 さて、先に『「こんにちは。」を 表示する』というプログラムを示したが、あのプログラムがMind 内部でどのように実行されているかを説明しよう。
全体のプログラム

「こんにちは。」を 表示する
 まず、最初はスタックが空になっていると仮定する(下図)。

 次いで、下の処理が実行されると、
最初の実行

「こんにちは。」を
 スタックは次のようになる。

  こんにちは

 文字列が「実行」されるという言い方に妙な感じを受けられるかも知れないが、Mind ではプログラム内に記述されたすべての単語が1つ1つ順番に実行されるというきわめて単純な原理で処理が進んでいく。

 話を戻そう。上の図のように、『「こんにちは。」を』という処理が実行されることで、この文字列がスタックにデータとして積まれた。このあと、この文字がどういう運命をたどるかは知らないが、とにかく、この時点で「こんにちは。」の実行は終わった。
 処理は次に移る。
次の実行

表示する
 『表示』という機能は、表示すべきデータをスタックから受け取るように設計されているので、『表示』はスタックから「こんにちは。」という文字列のデータを取り出し、これをコンソールに表示する。
 この『表示』の動作により、スタック上にあった「こんにちは。」という文字列データは消えてなくり、スタックは再び最初の空の状態に戻る。

 ちょうど銀行で、客がいったんカウンターに置いた通帳などを行員が受け取るような動きに似ている。

 もう1つ別の例を示そう。次のMind プログラムをご覧頂きたい。
全体のプログラム

2に 3を 加える
 上のプログラムは3 つの単語から構成されている。「2」「3」「加える」である。
 ここで注目して欲しいのだが、Mind コンパイラは、この一連の文全体を眺めてから、この意図に沿ったオブジェクトコードを生成するわけではない。
 Mind はもっと単純なコンパイルを行う。「2」をコンパイルし、「3」をコンパイルし、「加える」をコンパイルする…という具合に。そして、これらがどのように実行されるかといえば、「2」が実行され、「3」が実行され、「加える」が実行されるのである。
 ではその様子をトレースしてみよう。以下に示す実行の様子は、実はMind の対話機能を使えば実際に目で確かめることができるのだが、Mind のシステムが手元にない読者にも理解してもらえるよう、対話の様子に似せたスタックを図示することにする。(注2、3)。
注2
対話機能で確かめる場合、第2 行目(「3を」)からのキー入力では、ス タックの自動リセットを避けるため、行の頭に空白を1つ入れること。
注3
Mind Version 7 以降では対話機能が無くなっている。以下は対話機能が有った時の挙動となる。(対話機能の復活は未定)
 まず、最初はスタックは空である(下図)。

 この状態で、「2に」を実行する。スタックには数値2が積まれる。次のようになる。

     2

 次に「3を」を実行する。スタックには、さらに数値3が積まれ、次のようになる。

     2        3

 最後に「加える」が実行される。「加える」という処理は、加算すべき2つのデータをスタックから取り出す。この瞬間、スタックは空になる。

 そして、「加える」は、加算結果(数値5)を再びスタックに返す。最終的にスタックは次のようになる。

     5

 最後に得られた数値はどうなるのかというと、このまま放っておけばよい。これに引き続く処理がきっとこのデータを取り出すことになるのだろうが、それはこの一連の処理の関知しないところである。

 1つ1つの処理を、その実行順に書き並べるようなプログラム言語を「手続き型言語」と呼ぶが、Mind は本当に、文字通り、手続を1つ1つ淡々と並べていく手続き型言語である。「仕様書がそのままプログラムになる」というMindの大きな特徴も、この動作原理に基づいている。

 他のプログラム言語に目を向ける。BASIC 言語での次のプログラムと対比してみよう。
A=2+3
 BASICの上のプログラムは、 「A」が実行され、「=」が実行され、「2」が実行され …というようにはならない。いったんこのプログラム全体が解釈されてから、最後にまとめて「しかるべき」オブジェクトコードが生成され、あるいは実行されるという間接的な方法によっている。したがって、細かなレベルではプログラム(ソースコード)と動作は一対一ではない。
 さらにいえば、上記の「A=2+3」は、Mindプログラムの「2に 3を 加える」と等価な展開ではない。もし等かな展開をBASIC で記述するとすれば次のようなものになるだろう。
2+3
 しかし、これはBASIC の文法としては許されない。なぜなら、2+3という計算によって得られた結果をどうするのかが記述されていないからである。
 ひるがえって、Mind で
2に 3を 加える
という記述がなぜ許されるのかといえば、計算結果が暗黙のデータ格納場所(すなわちスタック)に格納されるからである。Mind では、あらゆる演算において、計算結果は暗黙のデータ格納場所に格納する…という統一が成されているために、「どこそこへ格納する」というような指示はあえて行う必要がなく、省略するこ とができる。
 少し情緒的になるが、Mindの次の表記がそれをより表している。
2に 3を 加え
 末尾の「る」を外しただけだが、これに後続する何らかの処理を予感させる(注4)。
注4
Mindでは、単語末尾の送り仮名は最終的に無視されるので、「加える」でも「加え」でも処理は同じである。
 このような事象は何も計算結果だけでなく、入力されるデータにおいても同様である。たとえば、
3を 加え
は、日本語の意味としては「何かに3を加える」ことだが、コンピュータの動作としては、「暗黙のデータ格納場所に置かれているデータに3を加え、暗黙のデータ格納場所に返す」ことに相当する。
 このような原理は、まさしく、我々が日常の日本語のメッセージを他人に伝達したり解釈したりする手法そのものなのである。
 最後に示した「3を 加え」は、普通の日本語にたとえるなら、サンドイッチを作るとき、
普通の日本語

バターを塗り
という場合に近いだろう。上記では「何にバターを塗るのか」が省略されているが、大抵の場合にはこれで話は通じるし、少なくとも、日本語の文法として誤りではない。当事者の暗黙の了解となっている対象物(パン)があり、それに塗ることになろう。
 後続処理についても同様で、
普通の日本語

バターを塗り具を乗せる
 と変化しても、依然として対象物(パン)を明示するような記述は現れない。
 他の例でいえば、
普通の日本語

山田さんから受け取り佐藤さんに渡してくれ
というのも同様である。
 英語であれば代名詞などが必ず登場するはずの文章であっても、日本語では省略されることの方が多い。これらすべてを支えているのが暗黙のデータ/暗黙の格納場所であり、Mindでいえばスタックである。
 日本語で仕様書あるいは手続きを単に書き並べれば、それがプログラムになる…という理想を実現するには、このような日本語の特質にマッチした機構が必要である。Mind ではスタックという、コンピュータにとってきわめて身近なハードウェア機構をもってこれを実現しているため、自然さと実用性を両立できているのである。

 ちなみに、「日本語は論理的な表現には向いていない」という意見を耳にすることがあるが、そこには、主語や目的語の省略を表面的にとらえすぎたための誤解があるのではないだろうか。ここで述べたような機構をふまえた上で日本語を見直してみると、むしろ日本語はきわめて合理的であり、論理的な表現に向いた言語ではないかと、筆者は思っている。


 
 
単語定義
 
 

 次のプログラムはMind の文法として正しいのだろうか。
笑う
 「笑う」などという単語はMind に標準で備わってはいないので、そのままではエラーになるが、文法的に誤りというわけではない。単に未定義な単語が出現したというだけのことである。
 それが証拠に、次のように、
笑うとは 「わっはっは」を 表示することである。
とでも定義しさえすれば、先のプログラムは名実ともに正しいプログラムになる。
 この定義の後に、対話モードであれば、
笑う。
などと入力すれば、コンソールには
わっはっは
という文字列が表示される。
 もう気付かれたかも知れないが、Mind では、あらゆる文章をプログラムとして受け付けるのである。ちょっと思いついたものを並べてみよう。
Mindのプログラムとして有効

ビールを 飲む
水素と 酸素を反応させる
彼女を 誘って ディスコに 行く
 従来のプログラム言語のイメージとはだいぶ違うが、ここまでくると「プログラムというのは本当は何なのか」が見えてくるような気がしないだろうか。
 結局、手続き型言語の場合、「どのような状況で何をするか」がどんな方法であれ記述されていればよいのである。
 どのような文法(表記スタイル)によるかは、それは個々の言語プロセッサが解決すべきことで、プログラムの本質ではない。また、どのような語彙を使って表現するかも、言語プロセッサの問題であり、これまた本質ではない。
 どんな方法でもよいとなれば話は簡単で、我々が日常的に使っている言語(たとえば日本語)で記述するのが最も合理的で自然な方法であろう。逆に、いままで我々が プログラムらしさ を表す構成要素だと思ってきた記号・数式・関数といったものは、実はプログラムの本質ではないことに気が付かれたことと思う。