

コンピュータプログラミングにおいて、条件文は条件(ブール式)の値に基づいてプログラムの制御フローを指示します。条件式は、制御フローを変更する副作用なしに値に評価されます。
C言語など多くのプログラミング言語には、明確に区別された条件文と条件式があります。純粋な関数型プログラミングでは、条件式は副作用を持ちませんが、Lispなど、条件式を持つ多くの関数型プログラミング言語は副作用をサポートしています。
if-then-else文の構文は言語によって異なりますが、一般的な構文を擬似コードで以下に示します。条件プレースホルダーで表される部分は、真または偽のいずれかに評価される式です。真の場合、制御は後続条件に移り、完了すると後続条件に移ります。偽の場合、制御は代替条件end ifに移り、完了すると後続条件に移ります。else句は省略可能なので、この部分は省略できます。通常、後続条件と代替条件は、単一の文または文のブロックのいずれかになります。end ifelse alternative
条件が満たされれば、結果として、そうでなければ、代替案が提示される。以下の例も擬似コードで示されており、プレースホルダーを具体的なロジックに置き換えています。
在庫が0の場合は、メッセージに「新しい在庫を注文してください」と表示し、そうでない場合はメッセージに「在庫があります」と表示する。初期のプログラミング言語、特にBASICの方言では、if-then-else文にはgoto文しか含めることができませんでしたが、これは読みにくいスパゲッティコードになりがちでした。その結果、コードブロックによる制御フローをサポートする構造化プログラミングが普及し、ほとんどのBASIC派生言語やすべての言語で標準となりました。このようなメカニズムと原則は、PascalやModula-2を含むALGOLファミリーの言語に基づいています。構造化された方法でgotoを使用することは可能ですが、構造化プログラミングではこれが容易になります。構造化されたif-then-else文は構造化プログラミングの重要な要素の1つであり、C、Java、JavaScript、Visual Basicなどのほとんどの人気言語に存在します。
慣例として、else条件節は、then条件節と同様に、直前の最も近い条件節に応答します。しかし、 ALGOL 60などの初期の言語では、入れ子になったif条件文の意味が明確ではありませんでした。構文が不十分で、常に同じ述語節を指定できなかったためです。そのため、パーサーは、意図した入れ子階層内の、おそらく複数の節のいずれかと条件節をランダムに組み合わせてしまう可能性がありました。ifelseif
Aならば、BならばS 、そうでなければS2Aならば、BならばS 、そうでなければS2Aならば(BならばS )そうでなければS2終了Aならば(BならばS )そうでなければS2終了Aならば(BならばS 、そうでなければS2 )Aならば(BならばS 、そうでなければS2 )終了これはぶら下がりelse問題として知られています。言語によってさまざまな方法で解決されます(一部の言語では、明示的なブロック終了構文(など)または中括弧( ⋯ )end ifなどのブロック囲みによって解決されます)。{}
条件分岐は、多くの場合、else-if構文によって言語で実現されます。最初に真となった条件に続くステートメントのみが実行され、それ以外のステートメントはスキップされます。プレースホルダー擬似コードでは次のようになります。
条件1ならばブロック1、そうでなければ条件2ならばブロック2、そうでなければ条件3ならばブロック3 ...そうでなければブロック4、条件終了以下の擬似コードでは、ある店が商品に対して最大30%の割引を提供しています。割引が10%の場合、最初のif文は真となり、「30ドル支払わなければなりません「」が印刷されます。最初のif文より下の他のすべての文はスキップされます。
割引率が11 %未満の場合、「30ドル支払う必要があります。」と表示します。割引率が21 %未満の場合、 「20ドル支払う必要があります。」と表示します。割引率が31 %未満の場合、 「10ドル支払う必要があります。」と表示します。の代わりにを使用する場合は、 1 つだけでend if済みます。else ifelseif
ALGOL 68では、1968 年の「ドラフト レポート」( ALGOL Bulletin No. 26の補足として配布)では、まだ「短縮形」の条件文で太字のキーワードelsfが使用されていました。 [ 1 ]その後、「アルゴリズム言語 ALGOL 68 の改訂レポート」(1973 年)で スペルelifが標準化され、太字の単語とその「簡略形」の記号の両方がリストされており、 elif はコンパクト形式で に対応します。[ 2 ]if ~ then ~ elif ~ else ~ fi|:( ~ | ~ |: ~ | ~ | ~ )
Adaでは、elseifキーワードは2 つの単語のシンタックスシュガーです。PHP も、中括弧構文とコロン構文の両方で キーワード[ 3 ]をサポートしています。PerlとRuby は、複数のandステートメントで必要となる多数の中括弧を避けるためにキーワードを提供します。Python は、構造が中括弧ではなくインデントで示されるため、特別なキーワードを使用します。そのため、とを繰り返して使用すると、条件ごとにインデントを増やす必要があります。Visual Basic はをサポートしています。[ 4 ] 同様に、初期のUNIX シェル(後に POSIX シェル構文[ 5 ]にまとめられた)もelifを使用しますが、スペース、改行、またはその両方で区切る選択肢を提供します。elseifelseifelsififelseelifelseifElseIf
しかし、Algolから直接派生した多くの言語、例えばSimula、Pascal、BCPL、Cなどでは、この構文は存在しません。また、 Java、ECMAScriptelse ifなど、C の構文派生言語にも存在しません。これは、これらの言語では、条件文の後にブロックで囲まれなくても、単一のステートメント (この場合は) を記述できるためです。if cond...
条件文のシーケンス内のすべての項が単一の式の値をテストする場合(例:if x = 0、、、 else if x = 1… else if x = 2)、代替手段としてswitch文があります。switch文を持たない言語では、これらはif-then-elseを連鎖させたものとしてエンコードできます。
switch文は多分岐をサポートしており、多くの場合、式の値を定数値と比較し、最初に一致したコードに制御を移します。一致するものが見つからない場合のデフォルトアクションも通常用意されています。最適化コンパイラは、制御テーブルを使用してswitch文のロジックを実装することがあります。動的言語では、ケースは定数値式に限定されず、パターンマッチングにまで拡張される場合があります。右側のシェルスクリプトの例では、「*)」が任意の文字列に一致する正規表現としてデフォルトケースを実装しています。
Edsger Dijkstraのガード付きコマンド言語( GCL) は、ブール値のガード(条件に対応) とそれに対応するステートメントからなるコマンドのリストとして、条件付き実行をサポートしています。GCL では、ガードが真であるステートメントのうち、正確に 1 つだけが評価されますが、どれが評価されるかは任意です。このコードでは
G0 → S0の場合 □ G1 → S1 ... □ Gn → Sn フィ
G iはガード、S iはステートメントです。ガードのいずれも真でない場合、プログラムの動作は未定義です。
GCLは主にプログラムに関する推論を目的としていますが、同様の表記法はConcurrent Pascalやoccamにも実装されています。
Fortran 77までの Fortran における最も初期の条件文は、値 (整数型、実数型、倍精度型) が <0、0、または >0 であるかどうかに応じて 3 つのラベルのいずれかにジャンプする算術 if 文でした。[ 6 ]
以下のコードでは、 の値に基づいて、制御がラベルのいずれかに渡されますe。
IF ( e ) label1 、label2 、label3これは以下のシーケンスと同等です。
e_temp = e IF ( e_temp . LT . 0 ) GOTO label1 IF ( e_temp . EQ . 0 ) GOTO label2 GOTO label3gotoのように動作するため、算術 if は非構造化プログラミングであり、構造化プログラミングではありません。これは、 IBM 704コンピュータ上の Fortran の初期実装における唯一の条件文でした。そのコンピュータでは、テストおよび分岐オペコードには、3 つの状態に対応する 3 つのアドレスがありました。他のコンピュータでは、最後の算術演算に関連付けられた、正、ゼロ、負、偶数、オーバーフロー、キャリーなどの「フラグ」レジスタがあり、「アキュムレータが負の場合に分岐」、次に「アキュムレータがゼロの場合に分岐」などの命令が使用されました。式は1 回のみ評価され、オーバーフローが発生する可能性がある整数演算などの場合には、オーバーフローまたはキャリーフラグも考慮されることに注意してください。
算術IF文は、Fortran 90規格から廃止予定とされ、Fortran 2018規格では削除されました。しかしながら、多くのコンパイラは既存コードとの互換性を保つため、引き続きこの文をサポートしています。
他の言語とは対照的に、Smalltalkでは条件文は言語構造ではなく、クラス内でBoolean抽象メソッドとして定義されており、2 つのパラメータ (両方ともクロージャ)を受け取ります。にはとというBoolean2 つのサブクラスがあり、どちらもメソッドを定義しています。 は最初のクロージャのみを実行し、 は2 番目のクロージャのみを実行します。[ 7 ]TrueFalseTrueFalse
var =条件ifTrue: [ 'foo' ] ifFalse: [ 'bar' ] JavaScript はC 構文に似た if-else 文をサポートしています。次の例では、ランダムな浮動小数点数 (0 ~ 1 の値) が 0.5 より大きい場合に真となる条件があります。この文はそれを使用して、出力と出力をランダムに選択します。Math.random()<0.5表が出ましたね!またはテイルスを手に入れたぞ!。
if ( Math.random () < 0.5 ) { console.log ( "表が出ました!" ) ; } else { console.log ( "裏が出ました!" ); }条件式は以下のように連結できます。
var x = Math.random ( ); if ( x < 1 / 3 ) { console.log ( " 1人が勝ちました!" ) ; } else if ( x < 2 / 3 ) { console.log ( " 2人が勝ちました!" ) ; } else { console.log ( "3人が同点です!" ) ; }ラムダ計算では、if-then-else条件文の概念は、以下の式を用いて表現できます。
真 = λx. λy. x false = λx. λy. y ifThenElse = (λc. λx. λy. (cxy))
注:ifThenElse に左条件と右条件として 2 つの関数が渡された場合、選択した関数を実際に呼び出すには、ifThenElseの結果に空のタプルも渡す必要があります。そうしないと、 ifThenElse は関数オブジェクトを返すだけで、関数は呼び出されません。()
数値を定義なしで使用できるシステム(Lisp、従来の紙ベースの数学など)では、上記は以下のような単一のクロージャとして表現できます。
(( λtrue. λfalse. λifThenElse. ( ifThenElse true 2 3 ) )( λx. λy. x )( λx. λy. y )( λc. λl. λr. c l r ))ここでは、true、false、 ifThenElseはそれぞれ定義に紐づけられ、その定義はブロックの最後にスコープに渡されます。
これに対するJavaScriptによる実用的な例(厳密性を保つため、単一変数関数のみを使用)は以下のとおりです。
var computationResult = (( _true => _false => _ifThenElse => _ifThenElse ( _true )( 2 )( 3 ) )( x => y => x )( x => y => y )( c => x => y => c ( x )( y )));上記の多変数関数を含むコードは次のようになります。
var computationResult = (( _true , _false , _ifThenElse ) => _ifThenElse ( _true , 2 , 3 ) )(( x , y ) => x , ( x , y ) => y , ( c , x , y ) => c ( x , y ));数値が仮定されているシステムを除いた、前述の例の別のバージョンを以下に示します。
最初の例は最初の分岐が実行される場合を示し、2番目の例は2番目の分岐が実行される場合を示しています。
(( λtrue. λfalse. λifThenElse. ( ifThenElse true ( λFirstBranch. FirstBranch ) ( λSecondBranch. SecondBranch )) )( λx. λy. x )( λx. λy. y )( λc. λl. λr. c l r ))(( λtrue. λfalse. λifThenElse. ( ifThenElse false ( λFirstBranch. FirstBranch ) ( λSecondBranch. SecondBranch )) )( λx. λy. x )( λx. λy. y )( λc. λl. λr. c l r ))Smalltalk では、真偽の表現に同様の考え方が使われており、 と はシングルトンオブジェクトで、TrueifTrue False/ ifFalseメッセージに対して異なる応答をします。
Haskell はかつて、ブール型にこのモデルをそのまま使用していましたが、この記事執筆時点では、ほとんどの Haskell プログラムでは、ifThenElseとは異なり、別の関数でラップするか、このページの Haskell のセクションで示されているように再実装しない限り合成されない構文糖衣構造を使用しています。ifathenbelsec
多くのプログラミング言語は条件式をサポートしており、これは文とは異なり、制御フローを制御するのではなく、値に評価されます。条件式の概念は、 1950年代後半にジョン・マッカーシーが記号処理とLISPの研究中に初めて開発しました。
ALGOL 60およびALGOLファミリーの他のいくつかのバージョンでは、if–then–else式として使用できます。条件式を含めるというアイデアはジョン・マッカーシーによって提案されましたが、ALGOL 委員会はマッカーシーの数学的構文ではなく、英語の単語を使用することに決定しました。
myvariable := if x > 20 then 1 else 2複合文はすべて、それぞれ異なる閉じ括弧で終了(保護)されます。
IF条件THEN文 [ ELSE文 ] FI 簡略形式: (条件 | 文 | 文 )
IF condition1 THENステートメントELIF condition2 THENステートメント [ ELSEステートメント ] FI "簡略" 形式: ( condition1 | ステートメント |: condition2 | ステートメント | ステートメント )
この方式は、宙ぶらりんのelse文の問題を回避するだけでなく、埋め込み文BEGINシーケンスでandを使用する必要も回避します。END
CASE switch INステートメント、ステートメント、... [ OUTステートメント ] ESAC 「簡略」形式: ( switch | ステートメント、ステートメント、... | ステートメント )
CASE switch1 INステートメント、ステートメント、... OUSE switch2 INステートメント、ステートメント、... [ OUTステートメント ] ESAC CASEステートメント の「簡略」形式: ( switch1 | ステートメント、ステートメント、... |: switch2 | ステートメント、ステートメント、... | ステートメント )
選択条項の例(ブリーフ記号付き):
PROC月の日数 = ( INT年、月) INT : (月| 31、 (年÷×4=0 ∧ 年÷×100≠0 ∨ 年÷×400=0 | 29 | 28 ) 31、30、31、30、31、31、30、31、30、31 );
条件式は常にLispの基本的な要素でした 。純粋なLISPでは、関数が使用されます。Scheme 、Racket、Common LispCONDなどの方言では、次のようになります。
;; Scheme ( define ( myvariable x ) ( if ( > x 12 ) 1 2 )) ; 'x' の値に応じて 'myvariable' に 1 または 2 を割り当てます;; Common Lisp ( let (( x 10 )) ( setq myvariable ( if ( > x 12 ) 2 4 ))) ; 'myvariable' に 2 を代入しますHaskell 98では、 if式のみがあり、if文はありません。また、すべての式には何らかの値が必要なので、このelse部分は必須です。[ 8 ]他の言語で条件式で表現されるロジックは、通常、再帰関数でパターン マッチングを使用して表現されます。
Haskellは遅延評価なので、 ifなどの制御構造を通常の式として記述できます。遅延評価とは、if関数が条件と適切な分岐のみを評価することを意味します(厳密な言語では3つすべてが評価されます)。次のように記述できます。[ 9 ]
if' :: Bool -> a -> a -> a if' True x _ = x if' False _ y = yC言語および関連言語は、次のような条件式を可能にする三項演算子をサポートしています。
条件?真値:偽値
条件が真の場合、式は真値に評価され、そうでない場合は偽値に評価されます。次のコードでは、x > 10 の場合は r に "foo" が、そうでない場合は "bar" が代入されます。
r = x > 10 ? "foo" : "bar" ;if文を使って同じことを実現するには、複数の文が必要となり、r2回言及する必要があるでしょう。
if ( x > 10 ) r = "foo" ; else r = "bar" ;明示的なif-then文の方が読みやすく、三項演算子よりも効率的なコードにコンパイルされる可能性があると主張する人もいるが[ 10 ] 、簡潔な式の方が読みやすく、繰り返し節が少ないため優れていると主張する人もいる。
Visual Basicやその他の言語では、条件式として使用できる関数 `IIf`IIfが提供されています。ただし、`IIf` は真の条件式のように動作しません。なぜなら、常に真と偽の両方の分岐が評価されるからです。ただし、一方の分岐の結果は破棄され、もう一方の分岐の結果が `IIf` 関数によって返されます。
Tcl ではif、はキーワードではなく関数(Tclではコマンドまたはと呼ばれるproc)です。例えば
もし{ $x > 10 }ならば{ "Foo!"と表示する}という名前の関数を呼び出しif、2 つの引数を渡します。1 つ目は条件、2 つ目は真の分岐です。どちらの引数も文字列として渡されます (Tcl では、中括弧内のすべては文字列です)。
上記の例では、関数呼び出し前に条件は評価されません。代わりに、関数の実装はif条件を文字列値として受け取り、呼び出し元のスコープでこの文字列を式として評価する責任を負います。[ 11 ]
このような動作は、コマンドを使用することで可能になりますuplevel。Uplevelexprを使用すると、新しい制御構造を Tcl プロシージャとして実装できます (たとえば、uplevel を使用して while 構造を Tcl プロシージャとして実装できます)。[ 12 ]
実際には関数であるためif、値も返します。コマンドからの戻り値は、実行されたボディスクリプトの結果、または式がゼロ以外ではなく、かつ bodyN が存在しない場合は空の文字列です。 [ 13 ]
Rustでは、ifは常に式です。 は、実行されるブランチの値、または()ブランチが実行されない場合はユニット型に評価されます。ブランチが戻り値を提供しない場合、()デフォルトで に評価されます。式の型がコンパイル時ifにわかっていることを保証するために、各ブランチは同じ型の値に評価される必要があります。このため、他のブランチが に評価されない限り、 ブランチは事実上必須です。のない は、デフォルトで常に に評価される可能性があるためです。[ 14 ]else()ifelse()
以下は、rxの値に応じて1または2を割り当てます。
let r = if x > 20 { 1 } else { 2 };不要な値は省略できます。
x > 20の場合、println! ( "x は 20 より大きい" );と表示する。パターンマッチングは、条件文(if-then-else文やswitch文など)の代替手段です。Wolfram Language、MLなど、関数型プログラミング機能を備えた多くの言語で利用可能です。以下に、 OCaml言語で書かれた簡単な例を示します。
果物を一致させる| "りんご" ->パイを作る| "ココナッツ" ->団子餅を作る| "バナナ" ->混ぜる;;パターンマッチングの強みは、アクションだけでなく値もデータパターンに簡潔にマッチングできる点にあります。以下に、これらの2つの特徴を示すHaskellで書かれた例を示します。
map _ [] = [] map f ( h : t ) = f h : map f tこのコードは、関数mapを定義します。この関数は、最初の引数(関数)を 2 番目の引数(リスト)の各要素に適用し、結果のリストを返します。この 2 行は、この場合に考えられる 2 種類の引数(リストが空の場合(空のリストを返すだけ)と、リストが空でない場合)に対する関数の定義です。
厳密に言えば、パターンマッチングは常に選択構造であるとは限りません。Haskellでは、常に一致することが保証された選択肢を1つだけ記述することが可能だからです。この場合、パターンマッチングは選択構造としてではなく、単に名前と値を関連付ける方法として使用されています。しかし、パターンマッチングが利用可能な言語では、選択構造として頻繁に使用されています。
Python、Perl、PHP、Objective-Cなど、連想配列やそれに類するデータ構造を持つプログラミング言語では、条件付き代入を実装するためにそれらを使用するのが慣例となっている。[ 15 ]
pet = input ( "名前を付けたいペットの種類を入力してください: " ) known_pets = { "Dog" : "Fido" , "Cat" : "Meowsles" , "Bird" : "Tweety" , } my_name = known_pets [ pet ]匿名関数を持つ言語や、プログラマが変数参照に名前付き関数を割り当てることができる言語では、ディスパッチテーブルとして辞書を使用することで条件付きフローを実装できます。
条件分岐命令の代替手段として、分岐述語があります。述語とは、制御フローを変更する代わりに、命令を条件付きで実行できるようにするアーキテクチャ上の機能です。
この表は、各言語の最新の言語仕様を参照しています。仕様が存在しない言語については、公式にリリースされた最新の実装を参照しています。
else ifcase構造では、正規表現によるマッチングは、条件付きフロー制御の選択肢の一つとして利用できます。例については、こちらのStack Overflowの質問を参照してください。CASECASEWHENcond1THENexpr1WHENcond2THENexpr2[...]ELSEexprDfltENDif ... else if ... elseCASECASEexprWHENval1THENexpr1[...]ELSEexprDfltENDMERGE組み込み関数が追加されました。Fortran 2023 で C 言語のような三項演算子が追加されました。ifFortran 90 で廃止予定とされました。Fortran 2018 標準で削除されました。シンボルテーブル:「太字の
else if
」→「
elif
」;「簡潔な
else if
」→「
|
:
」)