構造化プログラミングでの「制御構造の組み立て」を学ぶ必要性と演習案
この記事について
プログラミングにおける重要なパラダイム(枠組み)の一つに「構造化プログラミング」があります。
この記事では、この「構造化プログラミング」における「制御構造」について、この構造を使って手順を構築することの難しさや、演習の提案などを書いています。
構造化プログラミングにおける制御構造を学ぶ必要性
システムに何か仕事をさせたいときには、システムが理解できる方法で「指示」する必要があります。
これには主に2つのパターンがあります。
①処理を一つずつの作業に分解し、手順の形で指示する
②(条件を指定して)作業を一括して指示する
これらは必要に応じて選択されますが、①の(手順の形の)指示を記述した「手順」を作ることは(手続き型)プログラミングと呼ばれるもので、大変多くのプログラミング言語で採用されています。
そこでは、以下の三種類の指示の組み合わせて「手順」を組み立てます。
「順次」ある作業が終わったら次の作業、というように順番に処理させる
「分岐」指定した条件に応じて、次に処理させる作業を分ける
「繰り返し」指定した条件の元で、手順を繰り返し実行させる
これは「制御構造」とも呼ばれます。そしてこの「制御構造で組み立てた手順」を「手続き」の単位として、これを組み合わせて(作業させたい)仕事全体を組み上げることを「構造化プログラミング」と呼びます。
この制御構造による手順の例として、例えば
果物箱を開けて、箱の中の果物のうち、リンゴをリンゴ箱へ、ミカンをミカン箱へ移して下さい。
それ以外の果物はそのままにしてください。
終わったら果物箱は閉めておいて下さい。
という処理を「手順として」指示する場合には、以下のようなものが考えられます(一例です)。
①果物箱を開ける
②以下の③~⑥を、果物箱のすべての果物で順番に繰り返す
[
③果物箱から果物を一つ取り出す
④もし、その果物がリンゴだったらリンゴ箱に入れる
⑤もし、その果物がミカンだったらミカン箱に入れる
⑥どちらでもない果物は戻す
]
⑥果物箱を閉める
これらの指示は、上から下に「順次」実行されますが、④⑤⑥は条件による「分岐」、③~⑥を含む②は「繰り返し」となります。
そして、このような「制御構造による(手順の)組み立て」をスムーズに行うためには、ある程度のトレーニングが必要だと思います。
最近は、「手順」の指示を「図」(流れ図)で行うものがあります(RPAなど)。
これは、プログラミング言語のような「文法や単語(機能語≓予約語)」などの知識が不要ですが、同じような制御構造で記述するものが多いので、「構造化プログラミング」のトレーニングは有効だと思います。
特に「繰り返し」が難しい(難航する方が多い)
私が行っていたプログラミング未経験者向けの研修のカリキュラムには、この「制御構造の組み立て」の演習を取り入れていたのですが、その際に感じたのは、「繰り返し」に苦労する人が多いということでした。
その「原因」についての私の考えは、次のようなものです。
① プログラミング言語で手順を書くときに、「繰り返し構造」の中に書く文は(プログラム文の文字そのものは変化しないのに)一回一回の繰り返しのたびに色々な「状態」が逐一変化している、というイメージが難しい
② そして、処理の結果として求めている「最終的な状態」を、そのような「状態が逐一変化していった結果で実現させる」ように組み立てることが難しい(状態の変化については、必要に応じて変数を使っていく必要がある)
難航していた研修性のほとんどは、上記の点を意識しながら実際の演習問題に取り組んでもらうことで克服することができていましたので、これらは原因としてはおそらく「遠からず」だったと思っています。
実際の研修の場では「状態の変化を『見える化』して意識してもらう」「『順次処理を折りたたむ』ことによって繰り返しの記述に持っていく」などの指導を行っていましたが、これについては機会があれば別の場で書きたいと思います。
制御構造の組み立ての演習問題案
がプログラミングを教えるときに使った練習問題のひとつに「文字で図形を描く」というものがあります。
これは、'*'あるいは' '(空白)と改行を出力することで、特定の図形パターンを表示する、というもので、制御構造の組み立てや変数を使った「処理手順の組み立て」の練習として適していると思います。
これらの問題については従来からプログラミング演習で使われていて、インターネット上にも多くの問題があります。
また、YouTubeでは解説動画が多く公開されています(特にインドが目立ちます)。
問題としては以下のようなものがあります(図形の名前は私が適当に付けたものです)。
入力した値に応じて図形の大きさが変化するようにプログラミングします。
【問題1】
【問題2】
【問題3】
もっと複雑な問題もありますが、「制御構造」や「変数」の扱い方を習得するという目的では、問題1の8問が解ければよいと思います。
ただし、「試行錯誤していたら解けた」ではダメで、あくまで「狙って、その狙い通りに解けた」でなければなりません。
プログラミング未経験にも関わらず、この課題をいきなり短時間で解ける方がおられました(観察範囲では、10~15%位の方がプログラミング経験者と同じくらいの早さで解けていたと思います)。状態の(時間的な)変化を「イメージ」するのが得意なのかもしれません。
Pythonによる演習環境
ここではPythonを使った上記の演習の環境について書いて見ます。
Google Colaboratoryを使えば、Jupyter Notebookの環境をパソコンにインストールする必要がなく(すなわちWeb上で)使うことができます。
Pythonで図形を描くための解説やサンプルの多くは、このような「一文字出力と改行の組み合わせ」ではなく、配列を使っているようです。
その方が処理内容を視覚的に理解しやすく、またPythonという言語に適しているかもしれませんが、限られた手段(平面上の)図形をで実現させる方が、特に制御構造の練習として有効と考えて、この形を選択しました。
ここでは、プログラムの記述を極力簡単にするために、
「num」整数値の入力
「ast」'*'の描画
「blk」' 'の描画
「cr」改行
という手段を以下の形で提供します。
【1】
class o_meta(type):
@property
def num(cls):
return int(input("Enter the numbers: "))
@property
def ast(cls):
print('*', end='')
@property
def blk(cls):
print(' ', end='')
@property
def cr(self):
print('')
class o(metaclass=o_meta):
pass
これを使って解答をプログラミングします。例えば四角形の描画であれば、解答として
【2】
sz = o.num
for i in range(sz):
for j in range(sz):
o.ast
o.cr
になると思います。
実行するためには、Google Colaboratoryであれば、コードセルに【1】を入力して実行した後、別のコードセルに【2】を入力して実行すると、以下のように四角形を描画することができます。
文字列を使うともっと簡単に解凍できてしまう可能性もありますので、これを課題にするためには文字列の使用を禁止する必要があるかもしれません。
また、Python言語を使用しているといっても、実際に使用するのは、for文、if文、range関数程度ですから、その文法さえ知っていれば比較的容易に取り組めるのではないかと思います。
もし、Python言語の習得も目的にするならば、このようなクラスを使用せずに、必要な記述をすべて書いてもらう方がよいと思います。
まとめ
これまでに、「構造化プログラミング」における「制御構造の組み立て」の説明と、それを学ぶ必要性、Pythonを使った演習案を書いてきました。
前述したように、「繰り返し」の教え方については、機会があれば別のところで書きたいと思います。
補足1 作業手順ではない形の「指示」方法
作業指示を「手順」ではなく「(条件を指定して)一括して指示する」例として、上記の「果物箱」の処理を
「果物表にある果物の名前をそれぞれ、リンゴをリンゴ表へ、ミカンをミカン表へ、それ以外はその他表へ記載する」
と変更した上で、これをExcelのFILTER関数によるスピルで書いたものを挙げておきます。
D2セル → =FILTER(A2:A21,B2:B21="リンゴ")
F2セル → =FILTER(A2:A21,B2:B21="ミカン")
H2セル → =FILTER(A2:A21,(B2:B21<>"リンゴ")*(B2:B21<>"ミカン"))
FILTER関数はOffice365の最新バージョンのExcelで使用可能です(他のバージョンのExcelでは使用できないかもしれません)。
このような指示の仕方は、例えば「リンゴ表」ならば
リンゴ表には、
果物表にある果物の中の、
リンゴの果物名、を書く
と言っているのと同じで、データの固まり(集合)を表現・指示している、と言えます。
これは「作業手順」ではないので「制御構造」はありません。
他には、関係データベース(リレーショナルデータベース、RDB)への指示で用いられる「SQL」言語でも、主として同じような「一括指示」を行います。
ExcelやSQLが「作業手順による指示ができない」ということではありません。例えば、 Excelの数式ではLAMBDA関数の再帰呼び出しやIF文、変数を使うことで、繰り返しや分岐という手順を記述することができますし、SQL(SQL99以降)でも再帰を使うことで同様のことができます。
あるいは、どうしても作業指示に「手順」を使わなければならない場合があります。例えば「作業指示の前後関係に制約がある」場合などです
(例としては、「移動」を「コピーと削除」で実現するために、最初にコピーしてから次にコピー元を削除する、など)
補足2 コンピューターへの直接指示する方法は「手順」
従来から使われているコンピューター(ノイマン型)の装置に対して「直接」(機械語で)指示する方法は、あくまで「手順」です。
ですから、一括指示の例として挙げたSQLの場合には、関係データベース管理システム(RDBMS)が介在して、指示を一旦「手順」の形に「変換」してからコンピューター(装置)に実行させています。
一括指示においてシステムの性能を引き出すためには、その動きに応じて最適な指示や構成(実行計画)を考える必要がありますが、それにはまた別のスキルやトレーニングが必要です(ミックさんの書籍は、とても参考になります)。
補足3 変数や代入文の理解から
ある論文では、以下のようなプログラムの代入文で「aとbの値はどうなるか?」という問題を例にして、プログラミング未経験者が「変数」「代入文」を、色々な意味に解釈してしまう可能性がある、と指摘していました。
int a = 10;
int b = 20;
a = b;
正解としては「a = 20 , b = 20」を期待していましたが、この論文に挙げられていた「解釈」の例は、次のようなものでした(挙げられていた解釈は他にもあります)。
「a = 20 , b = 0」 bの中身がaに移るからbは空(0)
「a = 30 , b = 20」bの値がaに加えられる
「a = 30 , b = 0」bの中身がaに加えられる(bというコップの水がaに注ぎ込まれるイメージ)
「a = 10 , b = 10」代入の方向の誤り
「変化なし」単なるaとbの比較文だから
「変化なし」aとbの値が違うのに「等しい」という意味不明の文
同じ論文の中では、プログラミング言語の文に「具体的な物理現象のイメージを与え過ぎること」が誤解につながってしまう可能性がある、という主張もあったと思います。
プログラミング(言語)を教える際には、特に最初の段階で(誤解がないように)十分注意する必要があると思います。