現在では、パーソナルコンピュータは、電子式多機能ファックス、あるいは最近では、多機能テレビとして考えるのが普通になってきました。しかし、基本を抑えるには、これはやはり名前の通り、計算機械であると考えるのが理にかなっています。通信機能や画像処理は、あくまでも、手の込んだ複雑な応用計算の結果としてはじめて可能になっているのです。
じゃあ、計算だからということで、例えば、
3 + 5 =
と書いて入力すれば結果がポンとでるというわけにはいきません。いや、そうなるようにアプリケーションをつくればそうなりますが、コンピュータの中では、何をどうしているのかを問題にしたいわけです。
MopsないしForthでこれを実行する場合は、次のようになります。
3 5 +
これで終わりです。短いでしょ!短かければいいというものでは必ずしもありませんが、実に簡潔です。実際にこれをMopsに書き込んで(各文字の間には半角空白が必要です)enterキーを押せば直ちに確かめられます。以下、一般論から動作を説明します。
コンピュータの内部の仕組みは、大雑把にいえば、電気符号化されたデータを入れて保管しておくための記憶装置と、データに対して計算したり、変形したりする操作を加える中央演算装置(CPU)といわれる部分があります。最近は機械が複合化されているので、記憶装置に該当する部分と演算装置に該当する部分の二つにだいたい分けられる、という方がいいのかもしれません。
特別な場合を除けば、コンピュータでは、入力される数値はいったんメモリーに保管されます。この格納のためのメモリーの小区画は、"変数"と呼ばれるのです。普通の、というかForth系以外のプログラミング言語では、変数には必ず名前をつけないといけないものがほとんどです。そのため、まず変数を宣言します。この宣言で、「ここではこれだけの変数が必要だから。まず充分なメモリー領域を確保して、各区画とこれこれという名前とを結びつけてくださいよ」と知らせるのです。この命令を実行する部分が、コンパイラとかインタープリタといわれるソフトウェアです。正確には、コンパイラは、これを実行するんじゃなくて、これを実行するための機械への命令の束を作り上げるんですが。コンパイラ、インタープリタは、次回(多分)にすこし説明します。
さて具体的なMopsの動作を説明しましょう。"3"と書いたところで、予め準備されたメモリ(
データスタック)の一区画に数値3を格納します。次に、"5"と書いたところで
データスタックの一区画、前に3を格納したところの隣に5を格納します。そして、"+"と書いたところで、その前に二つ格納した値を計算装置に送った上でその格納部分を廃棄してしまい、足し算した結果を、また一個目の要素として
データスタックに格納します。結果を確認するには、
データスタックの最後に書き込まれた部分の中身を確認すれば良いわけです。
たかが足し算ですが、これだけのことをするわけです。いずれにせよ、メモリーから値を取り出し、それを加工して、結果をメモリーに格納する、という作業は、コンピュータが動作する際の最も基本的で原始的な手順といえます。
Mops/Forthでは
データスタックという名前の一時的な変数のためのメモリー領域が予め準備されているのが特徴です。これがないと、もう少し準備が必要になります。擬似C言語断片風に、この計算の実行手順を表現してみましょう。すると、
int a = 3;
int b = 5;
int c;
c = a + b;
のようになります。かなり怪しいな。これは、多分、正確には何のプログラミング言語でもありません。
プログラミングを少しご存知の方は、int変数a,b,cを宣言し、aに3を代入して...なんていう風に抽象的な、というか、すでにプログラミング言語の論理の世界で生きている言葉で、はじめから考えてしまいます。まあ、それがこの手の言語の狙いなのですが、ここでは機械が実際にしていることに注目したいわけです。そこで、ベタで見てみましょう。
上のような、a, b, c,は普通、変数と呼ばれます。英語ではVariable、つまり、変わりうるもの(値)というような意味です。内容として数値を持っていて、その数値は入れ替えができるということです。これは、機械としては何かというと、大抵の場合、記憶装置(メモリー)のなかのどこか一区画に付けた名前ということになります。
はじめの"int a"という宣言で、変数としてのaには記憶装置の一小区画が結びつけられるわけです。"int"はプログラミング言語でよく使われる整数(Integer)の意味の略語です。宣言のときにこの変数の中身はどんな種類の数になるのか(整数なのか、小数なのか、など)を付け加えておくことで、どれくらいの大きさの区画を取っておけば良いかが決まるわけです。具体的に必要な大きさは機械によって違います。b,cについても同様です。
そして、この変数名aに"= 3"と続けることで、そのメモリーの区画に"3"という数値が格納されるわけです。言語としての解釈は、変数への値の代入、ということですね。bの場所には5が格納されます。
Java(とかC)言語の入門なんかだと、ここで、"="は数学(算数)でいう等号と外見は同じだけれども意味は同じじゃないから注意せよ!みたいな説明がつきます。"="は"互いに等しい"という意味ではなく、"右側の値を左側に代入する"という意味なのだ、と。だから、C言語(JavaやC++など、C言語系は皆そう)では、"5=a"とやってもエラーになるだけで、何の意味もありません。"イコール"という意味なら、反対にしたって同じなはずですから。もちろん、移項とかも無意味です。意味が違うんなら、違う記号を使えばいいともいえるわけで、現にPascal言語(今では、DelphiやKylixで有名ですね)では":="という二つ組み合わせた記号を使います。代入がでてくる場面は多いので、記号を一つにしておけば、かなり字数が減らせる、というのが、C言語が混乱を招く記法を敢えて導入した多分最大の動機でしょう(単なる想像ですが)。
そして、いよいよ計算です。足し算の式のようですが、"="が"右側を左側に代入"という意味なわけですから、右から見ていきます。コンピュータが実施する順番で見て行くと、まず、変数aに当たるメモリーから値(ここでは3)を計算装置に読み込みます。次に、変数bに当たるメモリーから値(ここでは5)を計算装置に読み込みます。そして、これらの数値を足し合わせる計算をします。計算装置は瞬時に結果を得るでしょう。これで、右側(右辺)は終わりです。ここで得られた結果が、
はじめに変数cに割り当てられたメモリー領域に格納されます。これで、全てのプロセス終了です。結果を知りたいなら、変数cに割り当てられたメモリーの中を取りしてみればいいわけです。
少し説明が長過ぎましたね。要は、Mopsの場合と同じことをやっているわけですが、変数の領域をその都度宣言で作り出して名前をつけないといけないため、幾分、余分なソースコードが必要になるのです。この"余分"は、実行する内容が高度になるにつれて増大して行きます。Mops/Forthでは変数は
データスタックに格納するという大前提を置いてしまったことで、コードから領域の準備と値の格納に当たる部分を削り落とすことになりました。他の言語では、変数への代入、という数学用語で説明することで、メモリーだナンだという機械操作の汚らしい部分に抽象的な衣装を着せました。いや、私個人は別にメモリーをいじるのを汚らしいと嫌うセンスは共有していませんが(程度問題)、一般にはそのように考えられたのです。
クドくて申し訳ありませんが、いくつかここで細かいことについて補注しておきます。まず、語順について。"3+5"を"3 5 +"と書く語順が、よく非難というか嘲笑されます。ですが、C風言語での計算の仕方を見てください。コンピュータはa -> + ->bという順番では実行しないんです。まさに、a -> b -> +という順番で実行するのです。C言語風のコードではコードを読み込むときに行ったり来たりして、順番を入れ替えているのです(この機能を提供するソフトウェアをパーサ(parser: 構文解析機)と呼びます)。機械語に変換してから実行する場合は、その変換に少し手間取る程度ですみますが、そのまま解釈実行できる環境を考えると、かなり時間のロスになります。普通のプログラミング言語は、このように読み込みの際に行ったり来たりして、コンピュータの動作を隠して、コードに人間らしい読みやすさを与えようとするわけですが、Mops/Forthでは、機械の動作を、その余分な細部をはぎ取って、単純かつ透明に見せることを目標としてきたわけです。
関連しますが、Mopsだってメモリー(上の場合、
データスタック)への格納を表現する部分をコードから切り落としてしまっているのだから、そこは隠していることになるのじゃないか、ともいえます。一面ではその通りです。普通、MopsというかForthの解説では
データスタックを強調せざるを得ないので、隠してはいられないのですが、コードからは隠しているといっていいかもしれません。これを突き詰めた先に、逆ポーランド記法という定式化があるように思います。Mops/Forthのような語順は逆ポーランド記法と呼ばれます。逆ポーランド記法という名前があれば、
データスタックなしでも、Mops/Forthの書き順は正当化できます。つまり、
データスタックをこの局面では正当に隠してしまうことができるわけです。正統なコンピュータ科学から見れば、これでMops/Forthの書法も安住の地を与えうるわけです。強いて私のような邪道を勧めるつもりはありませんが、ここには非常に難しい問題が潜んでいるように思われます(後々、尾をひくでしょう。この話^^;;)。
最後に、数値は"特別な場合を除けば"メモリーに格納されるという書き方をしましたが、つまり、そうしない場合もあるということです。直接、計算装置に送り込んでしまい、計算装置の中に値を保持しておくことがあるのです。その場合も、a b +の順で実行されることに変わりはありませんが。ただ、これは、計算速度を上げるための、一定の条件が満たされるときだけ利用可能な裏技、のようなものですから、普通は、変数はメモリーだと考えてもいいと思います。もっとも、Mopsはこの裏技、頻繁に使ってますが....。
ただ、実は、変数を使う諸言語とMopsとでは、実現されている結果に微妙な違いがあります -- 場合によっては決定的な違いです。変数を使った場合、
はじめに入力として与えられた3,5は、それぞれa,bの値として記憶に残っています(メモリーに、ですね)。ところが、Mopsでは一度使われた値は廃棄されてしまいます。Mopsで、使った後でも値を残したいときには、それを複製(コピー)して、水増ししてから使わなければなりません。これは、MopsないしForthとその他のプログラミング言語では前提としているロジックが少し異なるということを意味するのですが、そういう理論的なことばかりでなく、実際のプログラミングのスタイルにも影響を与える事柄です。考え方の枠組みの違いが実際のやり方(所作)に与える影響というのは、ものすごくビミョーで、自覚しにくいものです。そんなわけで、人によってはついて行けなくなるのです(^^;;)。もっとも、変数の値も、いつまでも残っているというわけではなく、各変数には、その種類に応じて有効期限があります。この分類をするのも、プログラミング言語入門のはじめの課題になっていることが多いようですね。Mopsは、資源は使えばなくなる、という実にもっともな前提で動いているわけですが。
最終更新:2019年01月01日 20:01