ソフトウェア プログラム編その8 ひとまとまりの処理に名前を付ける | |||||||||||||||||||||
前章では制御構造のことを説明しました。 前に挙げた条件分岐とループができれば、原理的には全てのプログラムが記述可能です。ではこれでめでたしめでたしかというとそうではありません。 同じようなことがいっぱいあるなちょっと昔の悪夢を思い出して頂きます。下は前の迷宮脱出プログラムの一部ですが・・・ 1014 LD 260 [230] 260番地に現在位置をセットする。 1017 SUB 260 15 北の方向に隣接した位置を求める 1020 CMP [260] 1 隣接位置が壁かどうか調べる 1023 JZ 1028 (壁だった場合東方向のチェックに移る) 1025 ADD 250 1 壁でなければ250番地の内容に1を足す 1028 LD 260 [230] 同様に東方向が壁かどうか調べる 1031 ADD 260 1 1034 CMP [260] 1 1037 JZ 1042 1039 ADD 250 1 1042 LD 260 [230] 同様に南方向が壁かどうか調べる 1045 ADD 260 15 1048 CMP [260] 1 1051 JZ 1056 1053 ADD 250 1 1056 LD 260 [230] 同様に西方向が壁かどうか調べる 1059 SUB 260 1 1062 CMP [260] 1 1065 JZ 1070 1067 ADD 250 1よく見るとなんだか似たようなことを4回繰り返しています。5行づつブロックが4つあって、2行目と4行目はちょっと違っていますが、他は同じです。 2行目の処理は単なる足し算で(SUBは引き算ですが−を足すと思えば同じです)足す値だけが違っており、4行目も単なるジャンプ命令でジャンプ先が違うだけです。 考えてみたら似ているのは当たり前です。この5行ブロックは、東西南北のどこかの方向が壁であるかどうかを調べている部分です。同じような処理になって当然ですね。 他の所にも同じようなものがありますね。おかげでプログラムが不必要に長く、読みにくくなっています。 不必要に長く読みにくいということは、すなわち面倒くさくて間違えやすいということです。例えば壁かどうか調べるためのアルゴリズムに考え違いがあって修正しなければならなくなったとしましょう。すると同じようなところを、この場合は4カ所直さなければならなくなります。 そこで少し考えてみてください。こういうブロックに例えばCHECKWALLとかいう名前が付けられたとしたらどうでしょう? すなわち CHECKWALL(NORTH_WALL) CHECKWALL(EAST_WALL) CHECKWALL(SOUSE_WALL) CHECKWALL(WEST_WALL) とでも書いておけば、各方向の壁かどうか調べられるとしたらすごく便利なんじゃないかとは思いませんか? 本当に便利なんです。そこで高級言語には絶対にこういう機能が付いています。
しかもあとから何かの理由で壁のチェックを別なところでしなければならなくなったとしても、1行追加するだけで済んでしまいます。 関数とサブルーチンこのような機能を高級言語では関数とかサブルーチンと呼んでいます。 サブルーチンはともかく、関数という言葉はたいていの人が覚えているでしょう?そう。あのいやな数学で出てきた
とかいったやつです。プログラム言語における関数もまあ似たようなものだと思っていて、それほど大きな間違いではありません(実はもっと広い概念なんですが) 両者ともほとんど同じような物なのですがその違いは
答えを返すとか返さないとか言うのはなんでしょう? 多くの場合ある処理をするときは、結局何かの値を計算していることが多いですね。上の例では「現在位置の周囲に何本道があるか数えて」います。この場合の答えとは数えた結果の数に他なりません。 PASCALの場合は関数を
という感じで定義します。 ところでカッコのなかにパラメータとかいう物がありますがこれは何でしょう? もし関数にしたい処理がどの場所でも全く同じ処理なのであればこのパラメータは要りません。でも前の例のように、大体は似てるんだけど、ほんのちょっとだけ違うということが大半です。 このほんのちょっとした違いだけで異なったプログラムを書いていたら大変です。 このパラメータというのは、関数やサブルーチンにこのちょっとした違いを教えてやるための仕組み、とでも考えておけばいいでしょうか。 ですからこの例ではパラメータは1個しかついてませんが、実はいくつでもつけることができます。 またパラメータにしても関数の答えにしても、その実体は変数(すなわちあるメモリーの場所)です。変数である以上、以前説明した「型」を指定してやらないと困るのは分かりますね。 PASCALでは具体例には以下のように書いたりします。
これをどこか適当なところに書いておけば、プログラムの別なところで
みたいに書くと、RootCountという関数の答え(Pという位置の周囲の道の数)がYという変数に代入されます。Pという場所の値を様々に変えてやるだけで、迷路の中のどの場所の周囲の道の数でも勘定できるわけです。 同じくサブルーチンの場合は
というような感じで書いて、プログラム中でサブルーチンの名前だけ書けばそこでそのサブルーチンの中身が実行されます。 みんな仲良く幸せに??このようにサブルーチンや関数というのはすごく便利な物ですが、その利点はごちゃごちゃ処理を書かなくてもいいというためだけではありません。例えば プログラムの大枠はこれで完成した! あとは各関数を作ればいい! そのくらいならあいつにやらせたって構わないな! ということができることです。 今までのやり方でプログラムの一部を他人に任せようとしたら、一体どういうことになったでしょう?確実にひとりでやった方が速いということになります。 でもサブルーチン化できれば、サブルーチンの動作の仕方だけをきっちり教えておくだけで他人にそこを任せることが簡単になります。 いやそれどころか、 そういえばこういう機能の関数は既にあいつが作っていたぜ! なんてラッキーなことさえ起こるかも知れません。 実際、市販のコンパイラなどを買ってくれば、必ずライブラリという物が付いてきます。これは非常によく使う様々な機能を持ったサブルーチンや関数のセットに他なりません。 そういえば前に高級言語の高級な由縁に「使い回ししやすい」と書きました。 そう書いたのはこのサブルーチンという機能が非常に強力だからなのです。 でも同じことなら機械語だってできるんじゃないの?と聞かれるかも知れません。確かに機械語にも少々ややこしいにしても、サブルーチン機能はついてます。しかし、様々な制限があって、高級言語でやるほど簡単には行かないんです。 サブルーチンや関数の別な利点サブルーチンや関数の利点はこれだけではありません。特に実際にプログラムを作る際には、これがあるとないとでは天地の差があるのです。 そのためには前に迷宮脱出のアルゴリズムを考えたときのことを少し思い出してください。 あのときはどう考えたでしょうか? まず最初は左手の法則を思いついて、以下のようにその法則を少し詳細に分析しました。
これだけではプログラムなんて組めないと前は説明しましたね。でももし以下のような機能の関数があったとしたらどうでしょう?
すると上のアルゴリズムが
ちょっと待て!関数の中身がないのにプログラムと言えるか!と思われるでしょう?当然です。もちろん上のプログラムはまだ未完成です。 でも考えてみてください。「迷路から脱出しろ」というのはひどくとりとめのない話です。それに対して例えば「後ろの方向を求めよ」というのは具体的で分かりやすく、しかも簡単な話ではありませんか? 見ただけではどうしていいか分からないような問題でも、よく分析してみればそれより規模の小さい簡単な問題の組み合わせであったと言うのは良くある話です。科学とは問題をこういう風に分析して解決する手段です。つまり、あるややこしい問題が与えられた場合、
じゃあこういうやり方で解決できない問題は、プログラムが書けないのか?と思うでしょう? その答えは はい!書けません! です。 人が考えてどうやっていいのか分からないのだから、どうしようもありません。ここまで読んで「じゃあコンピューターに任せろ!」なんて人はもういないと思いますが・・・ |