入出力など,副作用のある計算をするときには式を評価する順番が重要になる。OCaml にもそのための制御構造(control structure)がある。
逐次実行
1つの方法は let ~ in を使うこと。let 以下が評価された後に in 以下が評価される。
# let () = print_string "Hello, " in
print_string "world.\n";;
Hello, world.
- : unit = ()
複数の式を ; で区切って書くと左から実行する。全体の値はいちばん右の式の値。途中の式の値は捨てられる。
# print_string "Hello, "; print_string "world.\n";;
Hello, world.
- : unit = ()
条件分岐
if をつかう。then 節が unit型の式であるときに限って,else 以下を省略できる。
# if true then print_string "Hello, world.\n";;
Hello, world.
- : unit = ()
これは,条件が偽なら何もしない,ということ。
# if false then print_string "Hello, world.\n";;
- : unit = ()
begin ~ end
; と if では if のほうが結合強度が強く,then節や else節の途中で ; が出てくるとそこでif式全体が終わりだと判断される。
# let f b = if b then print_string "Hello, "; print_string "world.\n";;
val f : bool -> unit = <fun>
この関数は引数(=ifの条件)が偽なら “world.\n” だけが出力される(引数に関係ないから)。
# f true;;
Hello, world.
- : unit = ()
# f false;;
world.
- : unit = ()
もし,真の時に “Hello, world\n” を出力し,偽の時には何もしたくないなら括弧で囲む。
# let f2 b = if b then (print_string "Hello, "; print_string "world.\n");;
val f2 : bool -> unit = <fun>
# f2 true;;
Hello, world.
- : unit = ()
# f2 false;;
- : unit = ()
または括弧の代わりにbegin ~ endをつかう。こっちのほうが「よいスタイル」だと推奨されているらしい。
# let f3 b = if b then begin print_string "Hello, "; print_string "world.\n" end;;
val f3 : bool -> unit = <fun>
# f3 true;;
Hello, world.
- : unit = ()
# f3 false;;
- : unit = ()
繰り返し
while は
while [式1] do [式2] done
という形をしていて,式1が真であるあいだ式2を繰り返す。while を使った fact の例:
# let fact n =
let i = ref 1 and res = ref 1 in
while (!i <= n) do
res := !res * !i; i := !i + 1
done;
!res
;;
val fact : int -> int = <fun>
# fact 5;;
- : int = 120
for は
for [変数] = [式1] to [式2] do [式3] done
または
for [変数] = [式1] downto [式2] do [式3] done
という形をしていて,[変数]を整数[式1]から[式2]まで順に束縛しながら[式3]を評価する。for を使って fact を定義してみよう。
# let fact2 n =
let res = ref 1 in
for i = 1 to n do
res := !res * i
done;
!res
;;
val fact2 : int -> int = <fun>
# fact2 5;;
- : int = 120