命令型プログラミング(F#)

F# はマルチパラダイム言語だ。次の3つのパラダイムをサポートしている。

ここでは命令型プログラミングを紹介。
ちなみに、命令型ってのは要するにフツーのプログラミング方法。色んな変数をいじりながら(状態遷移させながら)、「逐次実行」「繰り返し」「条件分岐」を繰り返してプログラムを書く方法。対義語(?)は関数型のような宣言型プログラミング。

mutable キーワードを付けると「代入」が可能になる

#light
let mutable str = "hello"  // mutable キーワードをつける
printfn "%s" str

str <- "good evening" // 「代入」が可能
printfn "%s" str

F# では「定数」がデフォルトで、mutable 指定された場合のみ「変数」になる。これは C/C++ とか「普通の」言語とは逆だ。
単純で些細なことだけど、この F# の思想は素晴らしいと思う。変数よりも定数のほうが読みやすいし、バグが生じにくい。だから僕は、 C/C++ にしても C# にしても、出来る限り const やら readonly 指定をつけるようにしている。それだったら、逆に変数にしたいときだけ mutable 指定するほうが絶対ラクだし、安全だ。

レコード型のフィールドにも mutable が使える

#light
type Person = {
  name : string
  mutable age : int  // mutable なフィールド
}

let john = { name = "john"; age = 20 }
printfn "%A" john

john.age <- 25  // 年齢を代入
printfn "%A" john

配列は mutable

純粋な関数型言語ではリスト一辺倒な感じだけど、F#には配列型も用意されている。配列とリストは対照的なデータ構造だ。

リスト 配列
長さの変更 可能 不可能
要素の変更 不可能 可能
#light

let array = [| 1; 3; 2; 5; 2 |]
printfn "%A" array

array.[0] <- 7; // 代入
printfn "%A" array

for 文

F# には for 文もある。これは配列の処理なんかに便利。

#light
let array = [| 1; 3; 2; 5; 2 |]

for a in array do
  printfn "%d" a

for i = 0 to Array.length array - 1 do
  printfn "array.[%d] = %d" i array.[i]

参照型 ref type

mutable と似たような「代入」を実現する方法として、参照型を用いることが出来る。名前から想像が付くように参照型とはポインタみたいなもので、参照先の値を複数の識別子で共有することが出来る。

#light
let strref1 = ref "hello" // 参照型を宣言
let strref2 = strref1     // 参照先を strref1 と strref2 が共有

(* どちらも "hello" が表示される *)
printfn "value of strref1 = '%s'" !strref1
printfn "value of strref2 = '%s'" !strref2

strref1 := "good evening" // 参照先を変更

(* どちらも "good evening" が表示される *)
printfn "value of strref1 = '%s'" !strref1
printfn "value of strref2 = '%s'" !strref2

参照型を複数の関数で共有

参照型は面白い使い道がある。複数の関数で一つの参照型を共有することが出来るのだ。

(* 3つの関数を定義 *)
let increment, decrement, show =
  let counter = ref 0 // 参照型の整数カウンタ
  let inc () = counter := !counter + 1
  let dec () = counter := !counter - 1
  let shw () = printfn "counter = %d" !counter
  inc, dec, shw  // 3つの関数のタプルを返す

increment ()  // !counter = 1
increment ()  // !counter = 2
decrement ()  // !counter = 1
show ()       // "counter = 1" と表示される

同じようなことを C# で書いたらこんな感じかな。

class Counter
{
  static int counter = 0;
  public static void Increment() { ++counter; }
  public static void Decrement() { --counter; }
  public static void Show()      { Console.WriteLine( "counter = {0}", counter ); }
}

Counter.Increment();
Counter.Increment();
Counter.Decrement();
Counter.Show();