制御構造とは
制御構造とは、
コンピュータプログラムにおける命令の実行順序を決定する要素です。
手続き型プログラミングや
命令型プログラミングにおいて、プログラムのフローを制御するために不可欠な概念です。具体的には、条件分岐、ループ、
サブルーチン呼び出しなどが制御構造に該当します。
制御構造の種類
制御構造には様々な種類がありますが、主なものとして以下のものがあります。
無条件分岐 (ジャンプ): プログラムの実行位置を無条件に移動させます。
条件分岐 (選択): ある条件が成立するか否かによって、実行するコードブロックを選択します。
ループ: あるコードブロックを繰り返し実行します。
サブルーチン呼び出し: プログラムの一部を別の場所に移して実行し、元の位置に戻ります。
継続: プログラムの実行状態を保存し、後でその状態から再開します。
プログラム停止: プログラムの実行を終了させます。
制御構造の歴史
初期の
コンピュータでは、制御構造は
機械語の分岐命令によって実現されていました。しかし、プログラムが複雑になるにつれて、より構造化された制御構造が求められるようになりました。
1960年代には、
構造化プログラミングの概念が登場し、`goto`文の使用を避けることが推奨されました。`goto`文はプログラムのフローを混乱させやすく、デバッグや理解を困難にするためです。代わりに、`if-then-else`文や`while`文などの構造化された制御構造が使われるようになりました。
制御構造の要素
ラベル
ラベルは、コード中の特定の位置を示すシンボルです。`goto`文の飛び先や、ループから抜け出す際の目印として使われます。一部の言語では行番号がラベルとして使用されます。
goto文
`goto`文は、プログラムの実行位置をラベルで指定された箇所に無条件に移動させます。`goto`文はプログラムのフローを複雑にするため、現代のプログラミングでは避けるべきとされています。
サブルーチンは、プログラムの一部をまとめたもので、再利用可能なコードの単位です。手続き、ルーチン、関数、メソッドなど、様々な呼び方があります。
サブルーチンを使用することで、プログラムの構造化やモジュール化が容易になります。
1966年、ベームとヤコピーニは、任意のプログラムは`if-then-else`文と`while`文のみで記述できることを示しました。これは構造化定理と呼ばれ、
構造化プログラミングの基礎となりました。この定理は`goto`文を無くすことができることを示唆していますが、`goto`文が完全に不要であることを意味するわけではありません。
構造化された制御要素
プログラミング言語によって、制御構造の構文は異なります。多くの言語では、ブロックと呼ばれるコードのまとまりを定義するための仕組みを持っています。例えば、`begin...end`や`{...}`などがブロックを定義するために使用されます。
選択
if-then-(else)
`if-then-else`文は、条件が真の場合と偽の場合で異なるコードを実行するための制御構造です。様々なバリエーションがあり、`elseif`文を使って多分岐を実現することもできます。
パターンマッチングは、データ構造のパターンに基づいて処理を分岐させるための制御構造です。関数型
プログラミング言語でよく使われます。
switchとcase
`switch`文は、変数の値に基づいて複数の処理を分岐させるための制御構造です。`case`文を使って、特定の値に対応する処理を指定します。
ループ
ループは、あるコードブロックを繰り返し実行するための制御構造です。ループには様々な種類があり、それぞれ異なる目的で使用されます。
カウント制御ループ
`for`文などのカウント制御ループは、指定された回数だけコードブロックを繰り返します。ループ変数の増減や、開始値と終了値を設定できます。
条件制御ループ
`while`文などの条件制御ループは、指定された条件が真の間、コードブロックを繰り返します。条件をループの先頭で評価する場合と、最後に評価する場合があります。
コレクション制御ループ
`foreach`文などのコレクション制御ループは、配列やリストなどのコレクションの各要素に対してコードブロックを繰り返します。
汎用の繰り返し
`for`文や`do`文は、より複雑な繰り返し処理を実現するための汎用的なループ構造です。
無限ループは、終了条件が満たされない限り永遠に繰り返されるループです。イベント駆動型プログラムなどで使用されます。
ループの制御
`continue`文は、ループの先頭に戻り、次の繰り返しを開始します。
`redo`文は、現在の繰り返しを先頭から再実行します。
`retry`文は、ループ全体を最初から再実行します。
`break`文は、ループを中断し、ループから抜け出します。
ループ変化条件とループ不変条件
ループの正しさを検証するために、ループ変化条件とループ不変条件を使用します。ループ変化条件は、ループの終了を保証し、ループ不変条件は、ループ中の状態を監視します。
サブ言語としてのループ
Lisp方言では、ループを記述するためのサブ言語を提供することがあります。例えば、
Common Lispの`LOOP`などがあります。
構造化非局所制御フロー
構造化非局所制御フローとは、プログラムの実行の流れを、現在のコンテキストから離れて、事前に定義された場所から続行させる制御構造のことです。
条件
PL/I|PL_Iなどの言語では、プログラムの実行中に発生する様々な条件(エラーなど)を検出し、対応する処理を行うことができます。`ON condition GOTO label`のように指定します。
例外
例外は、プログラムの実行中に発生したエラーを処理するための仕組みです。`try-catch-finally`文を使用して、例外を捕捉し、適切な処理を行います。`using`文などを使い、例外処理を簡略化することもできます。
継続
継続は、プログラムの実行状態を保存し、後でその状態から再開できるようにする制御構造です。
提案された制御構造
途中にテストのあるループ
途中にテストのあるループは、ループの先頭だけでなく、途中に終了条件を記述できるループ構造です。
複数早期脱出と入れ子ループからの脱出
複数早期脱出は、複数のイベントが発生した場合に、対応する処理を実行して、ループから抜け出すための制御構造です。
COMEFROM
`COMEFROM`文は、指定されたラベルからプログラムの実行を始める、`GOTO`文の反対の制御構造です。`GOTO`文と対比して、ジョークとして提案されたものですが、制御構造の問題に対して新しい視点を与えるものでした。
まとめ
制御構造は、プログラムの実行順序を決定するための基本的な要素です。
構造化プログラミングでは、`goto`文の使用を避け、`if-then-else`文や`while`文などの構造化された制御構造を使うことが推奨されています。制御構造を理解することで、より効率的で、可読性の高いプログラムを作成することができます。