制御構造

入出力など,副作用のある計算をするときには式を評価する順番が重要になる。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