ループと制御構造体
Mathematica プログラムの実行とは,一連の Mathematica 式の評価を意味する.単純なプログラムでは,式はセミコロンで区切られ,1つずつ評価されることが多い.しかし,多くの場合は,式を繰り返し評価する必要があり,ある種の「ループ」を使う必要が出てくる.
| Do[expr,{i,imax}] | 反復変数 i を刻み幅 で から に増加させ,式 expr を繰り返し評価する |
| Do[expr,{i,imin,imax,di}] | 反復変数 i を刻み幅 di で から に増加させ,式 expr を繰り返し評価する |
| Do[expr,{i,list}] | i が list からの値を取って expr を評価する |
| Do[expr,{n}] | 式 expr を n 回評価する |
簡単なループ構成体

を

から

に変化させたときの
Print[i^2]を評価する.

を

から

まで刻み幅

で変化させるループを使い,

に対する割当てを行う.
| Out[2]= |  |
関数Doで使われる反復条件はTable やSum等の関数と同様に指定する.後者の関数でできたように,一連の反復指定を与えることで,Do式でも複数レベルでネストされたループを構成することができる.
ループを作り,

を

から

まで振り,各

で

を

から

までふる.
場合によっては,反復変数の値は変えずに,単に特定の操作を繰り返したい.Tableや他の反復関数を使ってもこの種の反復操作は行えるが,Do式でも行うことができる.

による割当てを3回繰り返す.
| Out[4]= |  |
| Nest[f,expr,n] | 関数 f を式 expr に n 回適用する |
| FixedPoint[f,expr] | 関数 f を繰り返して式 expr に適用し,結果の式が変化しなくなる時点で停止する |
| NestWhile[f,expr,test] | 結果の式に test を適用したものがTrueを返さなくなるまで,式 expr に関数 f を繰り返して適用する |
関数の繰返し適用
Doを使えば,反復変数をいろいろな値に振り特定の式を評価することで一連の操作を繰り返すことが可能である.それでも,「関数を反復的に適用する」に示したような関数型プログラミングの構成体を使うと,分かりやすく,また,効率的なプログラムを記述することができる.例えば,関数Nest[f, x, n]を使えば関数を繰り返し,再帰的に式に適用する,ということが可能になる.

を3回ネストさせる.
| Out[6]= |  |
純関数をネストさせ,前述の
Doの例で作った式と同じ計算をする式を作る.
| Out[7]= |  |
このように,Nestは,関数を指定した回数だけ繰り返し適用するのに使う.それでは,関数を繰り返し適用させ,結果が変化しなくなったら自動的に停止させる,という処理を行いたい場合はどうするのか.そのときは,関数FixedPoint[f, x]を使い定常点の探索を行うようにすればよい.
| Out[8]= |  |
関数FixedPointを使うことで,カーネルの評価プロセスそのものや,
等の関数操作をまねることができる.FixedPointでは,2回の逐次結果に変化がなくなるまで関数の適用が続けられる.一方NestWhileでは,任意の関数がTrueでなくなるまで続けられる.
| Catch[expr] | Throw[value]が現れるまで式 expr を評価し続け,現れた時点で値 value を返す |
| Catch[expr,form] | tag が form にマッチするThrow[value, tag]が現れるまで式 expr を評価し続け,現れた時点で値を返す |
| Catch[expr,form,f] | 値 value の代りに を返す |
評価処理の非局所的な制御
| Out[9]= |  |
ThrowとCatchを組み合せて使うと,Mathematica の評価プロセスを監視することができるため便利である.評価を監視したい式には,Catchを作用させておく.評価処理中にThrowが現れると,その時点で進行中の処理は停止し,それに与えられている引数の現行値が返される.
| Out[11]= |  |
Mapを使っても同じ結果を得ることができる.ただし,
Mapだと,評価中に
Throwが現れないときはリストが返されることになる.
| Out[12]= |  |
ThrowとCatchを使えば,関数的なプログラミング構成体における操作処理を特定条件が満たされるまで続行させ,満たされなくなった時点で中断させることができる.Throwで評価を中断すると,得られる結果は途中結果である.途中結果なので,式は,仮に最後まで評価を続けたときの式とは構成上多少違ってくることに注意してほしい.
| Out[13]= |  |
Throwがないため,上の式と同じ結果が得られる.
| Out[14]= |  |
| Out[15]= |  |
ThrowとCatchはともに大域的な働き方をする.Throwどこに,またどのように配されても,一度それが現れると,評価処理は必ず中断され,制御は直接Catchに戻される.
| Out[16]= |  |
関数を定義する.この関数は,引数に10より大きい値を入力した場合,
Throwを発生させる.
| Out[18]= |  |
| Out[19]= |  |
短いプログラムでは,Throw[value]とCatch[expr]の最も単純な書式を使うだけでよい.しかし,構成部分が増えプログラムが長くなると,Throw[value, tag]とCatch[expr, form]の書式を使った方がよいだろう.タグ tag と形 form を局所的なものとしておくことで,ThrowとCatchがプログラムの特定部分だけで機能するようにすることができる.
| Out[20]= |  |
| Out[21]= |  |
パターンで
Catchの認識するタグを指定してもよい.
| Out[22]= |  |
こうすればタグ

を完全に局所的なものとして維持できる.
| Out[23]= |  |
ここでの注意点は,Throwで使うタグは定数である必要はない.通常,それはどんな式であっても構わない.
スローのタグの値が4より小さければ内側の
Catchがキャッチし,
Do式の処理が続行する.4以上になったら,外側の
Catchで止められる.
| Out[24]= |  |
Throw[value, tag]とCatch[expr, form]の書式を使った場合,Catchの返してくる値はThrowに指定した第1引数 value になる.また,Catchの書式をCatch[expr, form, f]にすると,
が返される.
| Out[25]= |  |
| Out[26]= |  |
| While[test,body] | 条件式 test を判定し結果がTrueならば,式 body を評価する.条件式が真でなくなるまで式の評価を繰り返す |
| For[start,test,incr,body] | 式 start を評価し,条件式 test が真でなくなるまで,式 と式 incr の評価を繰り返す |
一般的なループ構成体
構造化アプローチを取るなら,Do,Nest,FixedPoint等の関数を使いループを構築するとよい.また,ThrowとCatchを併せて使えば,ループを監視,制御することも可能である.一方,構造にとらわれないループを作りたい場合は,関数WhileやForを使うとよい.任意条件下で繰返し処理を停止できるループを構築することができる.
Whileループは,条件が満たされなくなるまで実行される.
関数WhileとForは,C言語の
と
に構文上似ている.ただし,違いもある.例えば,Forループのコンマとセミコロンの使い方はC言語と逆である.
Forループの簡単な例を見てみる.

は

の値を1増加させる.
少し複雑な
Forループを作ってみよう.実行させると,ループは,条件式

が満たされなくなった時点で終了する.
WhileとForのループにおいて,まず評価されるのは条件式であり,その次に,本体の式が評価される.つまり,Trueにならなければその時点でWhileおよびForループは終了してしまう.このため,本体の式が評価されるのは条件式がTrueになるときだけである.
ループの条件式はすぐに偽となるので,本体の式は決して評価されない.
WhileやForによるループ,または,その他の手続きにおいて,式の評価は特定の手順に従って行われる.この評価手順を Mathematica プログラムの実行における制御フローと呼ぶ.
一般に,制御フローはなるべく単純なものがよい.制御フローが,プログラム実行中に生成される特定値に依存すればするほど,プログラムの構造や動作が分かりづらいものになってしまう.
関数的な構成体では,制御フローが非常に単純である.WhileやForのループでは,制御フローがプログラム実行時の条件式の値に左右されてしまうので,ループが複雑な構成になりがちである.とは言え,ループであっても,制御フローは,普通その本体で与えられた式の値に依存するようなことはない.
それでも,場合によっては,本体の式の値に依存した形でフローを変えてやらなければならない.これを行う方法として,まず,関数的なプログラミングの考え方に適合した手法,つまり,関数ThrowとCatchを使う方法が考えられる.さらに,Mathematica にはC言語で提供される制御フローの操作用関数に相当した各種の関数が用意されているので,それらを利用するのも便利である.
フローの制御関数

が

を超え,制御が
Break[]に達した時点でループが停止する.

のときは,
Continue[]に制御が行き,

の計算は実行されずにループが続行される.
Return[expr]を使い,戻り値を指定することも可能である.ネストされた関数式から一挙に退避できることから,Throwを非局所的なリターン機能と考えることもできる.エラー処理に利用すると便利である.
引数が5より大きいので,手続きでは最初の
Returnが使われる.
| Out[34]= |  |
引数が負の数のときはエラー値

を返すように関数を定義する.
| Out[36]= |  |
| Out[37]= |  |
Continue[]やBreak[]の関数はループの始点もしくは終点に制御を移すために使う.場合によっては,ループの外にある手続き内の任意の位置に制御を移したい.そのようなときは,転送先を関数Labelであらかじめラベル指定をしてから関数Gotoを使い実際に制御を移す.

が

を超えるまでループが続行する.
注意してほしいが,Gotoを使うには同じ手続き内にLabel指定がなければならない.ただし,Goto指定を使うとフロー構造が入り組んだものになり,プログラムがどう機能しているのか分かりづらくなるので使用には注意が必要である.