プログラムの基本構造
実際のプログラミング言語で書かれたプログラムであっても、疑似プログラムであっても、コンピュータプログラムは必ず次の要素を含んでいます。
- 入力
- 出力
- データ
- 演算
- 制御
- サブプログラム
これらをもう少し詳しくみてみましょう。
サブプログラム……ま、いっか。これは後回しにしましょう。
入力
キーボード、磁気ディスク、磁気テープ、光ディスク、通信回線等、コンピュータの外部から必要な情報を読み込むことを意味します。
一応、若い人向けに解説しておきましょうか。あまりにも古いんで(何せ90年代初頭に書かれているし・笑)、若干不安を感じたもので。
キーボードはいいですね。
磁気ディスク……今はフロッピーディスクなんてあんのか(笑)?最近めっきり見かけません(笑)。余計混乱すっかも。ええと、ハードディスク、なんてのがこの「磁気ディスク」に含まれます。
磁気テープ(爆)。ええと、大昔はパソコンで「音楽用カセットテープ」使って今のハードディスクのような事をやってたんですが……。ダメだ、そもそも若いコは「カセットテープ」知らねえか(苦笑)。
他にも、大型コンピュータでも記録媒体として大きな「オープンリールのテープ」状のものを使っていましたし、ファミコンのディスクシステム、なんかもこの磁気テープの一種なんですが……殆ど全て死滅致しました。
忘れて結構です(笑)。一体いつの時代の話だ(笑)?
光ディスク。今で言うCDとかDVDの類、ですね。90年代初頭はまだそこまで普及してなかったんじゃないかな?CDドライブ搭載パソコンってのが40万円以上したような時代ですし。まあ、今は記録媒体としてはすっかり主流となっています。
通信回線。これは今で言う「インターネット」って考えてまあ良いでしょう。
出力
CRTディスプレイ、プリンタ、X-Yプロッタ、磁気ディスク、磁気テープ、通信回線等、コンピュータの外部に情報を書き出すことです。
CRTディスプレイってあんた……。ええと、CRTってのはCathod Ray Tube、要するに「真空管」とかテレビの「ブラウン管」の事です(専門的には陰極線管、と呼ぶ)。が……今の人には「液晶ディスプレイ」の方が「フツー」でしょうね。
2011年から地デジだよ(笑)。もうこの「CRT記述」の「コンピュータ」テキスト、最低でも2011年までには改訂した方がイイぜ(苦笑)。
プリンタはまあいいでしょう。
X-Yプロッタ、って何じゃそりゃ(苦笑)。聞いたことありません。ああ、これによるとウソ発見器のようなモノらしいんですが……誰がそんな出力装置を一般家庭で使うか、っつうの(苦笑)。
データ
数(定数、変数)と文字(文字列)、または、それらを組み合わせるなどして、情報をコンピュータが処理できるかたちで、また処理しやすいように表現したものです。
コンピュータの内部構造にデータを格納する場所を確保するために、プログラムの最初の部分で変数宣言をおこないます。
下線部:亀田
何これ?アセンブラレベルの事言ってるのかしら?
少なくとも、高級言語(通大のテキストでは"高水準言語"となってる)では「変数宣言を行う」必要の無い言語、ってのもあるでしょう(例:Schemeとか)。大体、BASICで「変数宣言」なんてするか?
ウソ書いちゃいけませんよ。「プログラムの最初部分で変数宣言を行う」かどうかは、選んだプログラミング言語次第、です。
演算
データになんらかの形で処理を加えることを意味します。コンピュータの処理の基本は、演算によって求められた値を変数に代入していくことです。それを繰り返し、入力データを目的とする出力データに変化させます。
プログラミング言語にあらかじめ用意されている比較的単純な演算(加減乗除の4則演算等)を組み合わせて、実際に必要となる演算処理を行います。実際のプログラミングにおいて苦労するのは、理論的に何をすればよいのかわかっていても、それを現実に使える演算を用いて、どのように実現するかという点です。
制御
あるデータ、または、あるデータに演算を施した結果に着目して、演算処理の流れを変化させることです。
逐次、分岐、反復の3つを制御の基本3構造といいます。
下線部:亀田
まあ、間違っちゃいないんですが……。人によっては「基本4構造」ってのを定義している人もいますし、SchemeなんかのLisp系言語族では、理論的には、ある種「逐次と分岐だけで」プログラムを書ける、ってのを証明しちゃってますからねえ(しかも背景は数学理論で、数学的に「反復」を消してしまってる)。
いずれにせよ、この辺の話、ってのは「基本××構造」と言うより、一種の工学的スローガンなのです。実は際立たせて強調するようなものじゃない、ってばないんですよね。
ちょっと参考資料として、アラン・ゴールド著のPythonで学ぶプログラム作法から長くなりますが引用してみましょうか(原語版:Learning to Program)。
その昔(1965年)、エドガー・ダイクストラという技術者が「構造化プログラミング」という概念を提唱した。これは、すべてのプログラムは、順次実行、分岐、ループ、モジュールという4つの制御構造を組み合わせて構造化できるという概念である。順次実行
順次実行は、1つの命令の実行が終われば次の命令を実行するという、最も単純な制御構造である(図1)。MS-DOSのバッチファイルの制御構造は、単純な順次実行である。分岐
分岐は、1つのプログラムフローが複数のストリーム(流れ)に分岐されるときに発生する(図2)。実際のフローは、テスト条件が真になったか偽になったかに応じてどちらか片方のストリームに進んでいく。この性質上、この構造はしばしば「条件分岐」とも呼ばれる。分岐は、プログラムの意思決定部分であり、コンピュータに知性を与える構造である。分岐構造がないプログラムは、何度実行しても一連の命令を単純に同じ順序で繰り返すだけの実につまらないものだ。ループ
ループは同じ命令(または命令セット)を何度も繰り返し実行する構造である(図3)。通常、繰り返しの終了は、繰り返し回数を入れたカウンタか、または何らかのテスト条件(ファイルの最後まで到達したかどうかなど)により制御する。この構造により、同じ処理であれば、何度も開始させなくても1度で大量にこなせるようになる。また、何度も実行する命令を一度記述するだけで済むので、プログラミングの労力も大幅に削減される。ループは、分岐のジャンプ先が前の方であると考えれば、分岐の一種であると捉えることもできる。モジュール
モジュール(注)は、多数の命令で構成されるまとまった処理を再利用可能なコンポーネントにするための手段である(図4)。モジュールには、その他の3種類の制御構造を任意に組み合わせて入れることができる。できあがったコンポーネントは、プログラムのほかの部分にサービスを提供する「ブラックボックス」として使用される。一連の処理をコンポーネントにすることにより、利用する側のコードではその処理の詳細を気にする必要がなくなるのだ。また、同じコードをプログラム内の複数の場所から、場合によっては他のプログラムから再利用できるようになる。
注:モジュールは、プログラムを記述する際に必ず必要な制御構造というわけではない。実際、ダイクストラが提唱した構造化プログラミングの概念にはモジュールは含まれていなかった。しかし、モジュールは長年に渡ってプログラミングの統制手段として受け入れられてきた構造である。
下線部:亀田
ここで当然、「逐次=順次実行」ですし、「反復=ループ」です。
さあて、下線部引いたところを見れば分かりますが、「反復=ループ=分岐の一種」です。と言う事は、「制御の基本2構造〜基本4構造」のうちのどれが正しいのか(笑)?制御x構造、2≦x≦4だ、と(笑)。
それ考える前に、上の文献を見ると「モジュールはプログラムを記述する際に必ず必要な制御構造というわけではない」と書かれています。
勘の良い人は気づいたかもしれませんが、これは次のトピック「サブプログラム」の事なのです。
サブプログラム
他の部分と独立なひとまとまりの処理に名前をつけ、プログラムの他の部分で名前を呼ぶだけでそのまとまった処理を実行するようにするものです。関数と手続きの2つが基本です.
関数は式のなかで使われますが、手続きは1つの命令文として扱われます。
前半見ると、丸っきり「モジュール」と同じですよね。
後半に下線部付けましたが、何を言ってるのかちっとも分かりません(笑)。が、安心して下さい。半分以上大嘘です(爆)。あるいは、Pascalの表面上に表れている約束事の事なので、この辺は取り合えず無視してて結構です。あとでまとめてツッコミます。
ところで、実際問題「サブプログラム」なんて言い方はしません。古い言い方ですが、「サブルーティン」の方がポピュラーですよね。「サブプログラム」もある意味「玉川用語」です。
また、何故「サブルーティン」は「古い言い方」なのか?それは古いプログラミング言語(それは1973年登場のC辺りまで)の場合、プログラム同士に「主従関係がある」と言うとんでもないおかしな制約を課していたから、なんです(いや、下手すればC++辺りまで?Java辺りまで?いやいや、VisualBasicまでか???)。
現代的な立場では、特にプログラム同士に「主従関係」なんてありません。プログラムAとプログラムBは等価関係で、AからBを呼び出しても良いし、BからAを呼び出しても良いプログラミング言語の方が今じゃ主流なのです。
ですから、用語としては「モジュール」の方が的確でしょうね。「サブプログラム」なんて言っても形式的には「何も差が見られない」プログラムを別定義する必要性なんてないわけです。この辺の「サブプログラム」云々は忘れて構いません。少なくとも「90年代前半までの」常識で、21世紀のものじゃあ無いです。
では、ここで、「制御の基本x構造」、xは何だ?って問題を考えてみましょうか。いや、考える必要なんてあんまり無いんですけどね。
亀田の好みとしては「制御の基本2構造」で十分、です。つまり「逐次処理」と「分岐」さえあれば十分だ、と。何故なら「モジュールは必ずしも必要無いし」「反復は分岐で説明出来る」のなら、直交している公理はたった二つしかない、からです。
これ、何でこんな話になってんのか、と言うと、平たく言えば「数学者」と「工学者」のアティテュ−ドの差、と言い換える事が出来ます。
別に亀田は数学者でも工学者でも無いんですが、要するに、幾何学でやったと思いますが、数学者は「独立した基底をn個選べばそれでn次空間を定義するには十分だ」と言う思考回路だから、なんですよ。分かりづらい?要するに、公理系を定義する際に、「公理系第二で第三を説明出来る」ってのを基本嫌うのです。「だったら第三はいらねくね?」と。
計算規則を確立させるのが数学的な公理系の定義なんですが、数学者は通常、「慎重に」説明が重複するような要素は挿入しないんです。「最小限の」材料で「いろんな事柄を説明したがる」。
反面、割に工学者はその辺無頓着ならしくって、「基本」なんつっても数学的に厳密な話はしたがらないんでしょう。
教訓です。
- 数学者はミニマリスト的アプローチで、常に公理系は最小の要素に抑えようとする。
- 工学者はプラグマティスト的なアプローチで、数学的な公理の要素数をいつも肥大化させようとする。
ですから、理論面で言うと、コンピュータプログラムの「制御x構造」なんつってもその実態をマジメに問うのはバカバカしい、っちゃあバカバカしいのです。アホ臭くて討論する気も起きません(笑)。
コンピュータは基本的に、
- 外部からの情報を取り込む(入力)
- その情報を自分が処理できる形である場所に保存する(データ)
- それをある目的に向かって逐次変化させる(演算)
- 目的が達成されたところで、その結果を外部にしらせる(出力)
と言う順序で、処理を進めていきます。そして、我々がやらなくてはならないことは、入力されたデータをどのように、また、どのような順序で変化させたら目的のデータが得られるかを考えることです。
ここで注意することは、コンピュータが自主的になにかを行うのではなく、実際には、それらをコンピュータに人間がこと細かく指示、命令しなくてはならないということです。その指示、命令が書かれたものがプログラムです。
上の基本処理の流れから、入力、出力、データ、演算の4つがプログラムの基本構成要素として含まれることがわかります。
ところで、コンピュータにたいして指示を、ただ単に順番に与え一方向的な流れで演算処理を行いデータを変化させるだけでは、最終目的に達することは一般的にはできません。あるデータの内容によって、また、ある演算の結果によって、指示の流れを変え、演算の順序を変化させなくてはならないときがあります。また、同じような演算を何回もある回数だけ、または、ある条件を満足するまで繰り返し行う必要が生じることもあります。すなわち、コンピュータの処理の基本は、演算処理の逐次実行ですが、場合によっては分岐と反復を用いて演算の順序を制御しなければ、目的に達することはできないのです。この逐次、分岐、反復をプログラミングにおける制御の基本3構造といいます。
最後の基本要素であるサブプログラムは、我々人間の思考のしかたと、プログラミング方法論に深く関係してきます。これは、他の部分と独立なひとまとまりの処理があったとき、それを一言で引用しようというものです。数学でも、同様なことを行います。複雑に定義される関数や頻繁に使われる関数は、一度、厳密にその計算法が述べられれば、後は単に関数f(x)というような形で、いろいろなところで引用されます。
大きく複雑な問題に、どのように対処しなければならないかという問に対する一つが、分割統治と階層化です。分割統治とは、問題をいくつかの、互いに独立なサブ問題に分割し、それぞれのサブ問題の解決策を考えるということです。サブ問題が、まだ大きく複雑であれば、さらにその問題を細分化して、より小さな問題にしていきます。以下同様に、問題が十分小さく単純になるまで繰り返します。これが、階層化です。このとき、主問題のプログラム(メインプログラム)に対して、サブ問題のプログラムは、サブプログラムと呼ばれます。
この要素がなくとも、プログラムを書くことはできるかもしれません。しかし、それは書いた本人ですらも読むことが難しく、その内容の正しさを保証できない、後で手直しのしにくいプログラムになります。人間は、大規模かつ複雑な問題に対して(実際には、それほどの問題でない場合でも)、一度でその解決策を考え出すことは、まずできません。試行錯誤を繰り返すことによって、それは可能となります。そのためには、解決策が書かれたプログラムは簡潔で、読みやすく、処理の流れがなるべく単純でなければなりません。それを実現するための、一つの補助手段だサブプログラムなのです。
以上では、プログラムの基本要素をあげ、その意味と役割を簡単に述べました。データ、制御、およびサブプログラムの各要素については、節をあらためてさらに詳しく説明することにします。
下線部:亀田
まあ、特にツッコむところはありません。と言うか、ツッコむべきところはもうツッコんだ、ので。
よって注釈します。
ここの文の後半は、要するに「構造化プログラミング」の概念を「構造化プログラミング」と言う用語を用いずに解説しています。「分割統治」と「階層化」なんて言われても厳めしいだけ、なんですが、発想としては「その通り」ですね。児玉清状態です。
ただし、です。通大は現時点十進BASICを配布しているそうなんですが、そもそもBASICは「構造化プログラミング」言語じゃない、です。この「分割統治」「階層化」なんてやりたくてもやりづらい。原則的にgo to文とかjump構文で「アッチコッチに飛び回る」非常に「分かりづらい」ソースコードになっちゃう、ってのがBASICの特徴なのです。
そもそも歴史的には、FortranやBASIC等の古い言語(登場は1960年代以前)で書かれた、メインテナンスの難しい「グチャグチャのプログラム」が氾濫したんで、その反省で「構造化プログラミング」と言うアイディアが生まれた、って思ってあながち間違ってない、んです。従って、この説明は十進BASICを使う以上、無意味です。
また、過去の通大生の投稿見る限り、この辺の「問題の分割」が出来てない、んですよね。確かにBASICなら行番号に従って「一気に処理を記述しなければ」ならないような気になってきますし。ですから、そもそも「言語の選定」として大間違い、なんです。果たして通大生が悪いのか、使ってる言語が悪いのか(あるいはテキストが悪いのか・笑)。
「分割統治」と「階層化」のサンプルとしては<質問3609>と<質問3628>を参照。実際、問題を「互いに独立なサブ問題に分割し」「それぞれのサブ問題の解決策を考える」と言うことをやってる実例です。実は「構造化プログラミング」とは言っても、やってること自体はそんなに難しいわけではありません。
それは書いた本人ですらも読むことが難しく、その内容の正しさを保証できない、後で手直しのしにくいプログラムになります
これは警告、ですね。その通りです。
プログラミングの世界では
半年前の自分は他人
と言う格言があります。つまり、例え自分が書いたにせよ、「半年前の自作のコードさえ」読むのは大変だ、と言う意味なんです。
(ましてや他人の書いたコードならなおさら、です)
よって、コードを書く場合はいつも「可読性を心がけて……」と言うのが大事なんですが、ここでも、元々BASICは可読性としては「サイテーの言語」なんですよ(苦笑)。少なくとも現代的ではない、です。
後で具体例を挙げますが、コードの可読性を上げる際に一番重要なのは、とにかく「インデント」(字下げ)と「コメント」です。そう言う「現代的な習慣を教える」と言う意味では十進BASICの選択はやっぱり「大間違い」ですね。「タダで入手出来れば良い」ってもんじゃない。
試行錯誤を繰り返すことによって、それは可能となります
これも教訓です。
通大生の発言の典型例に「私はプログラミングが分かりません」と言うのが頻出なんですが、まあ、一つは「全然勉強(自習)してない」って意味があって、こう言う奴等はホントどーでも良い、んですが(こんな言い訳平気でやる奴等は教員免許剥奪してやるべきだ、とまで思います)、反面、「完璧主義者」も困ったもの、です。
最初に言っておきますが、
プログラミングは間違って当たり前だ
ってのが前提なんです。どんなケースでも、いや、プロでさえ、「最初からフルスクラッチで間違いないコードが記述出来る奴」なんてのはこの世に存在しません。いません。絶対にいない。
(どんなプログラムでも"バグ"は潜んでいる、って事を考えても明らか、です)
従って、実際は「間違いを修正しつつ」プログラムってのは作り上げられるのです。
どう言うわけか、「上手く動かない」のを苦痛に考える人がいるようなんですが、逆に言うと「上手く動かなくて当たり前だ」って事です。
人間、エラーを見ると「責められている」とか「俺は頭が悪い」とか考えがちなんですが、そうじゃなくって性格的には「楽観的」な方がプログラミングには向いている、と言う事を指しています。
実は、この「間違いの修正」の方が、プロでも事実上「一番時間を取られる」部分なのです(デバッギング、と言う単語を聞いた事があるでしょうか?)。つまり、「間違いは必ずある」んで、んな事で一々凹んでられない、って事なのです。
試行錯誤が一番大事で、「試行錯誤する事を厭わない」気質がプログラミングでは一番求められている性格なのです(そしてこれは、理工系では共通して求められている性格、でもあります)。
「試行錯誤」の実例が<質問3700>ですね。
(実際、出来たプログラムは通大で求められているものとしては明らかにオーバースペック、ですが)
0 コメント:
コメントを投稿