命令型プログラミング(F#)
F# はマルチパラダイム言語だ。次の3つのパラダイムをサポートしている。
- 関数型プログラミング (functional programming)
- 命令型プログラミング (imperative programming)
- オブジェクト指向プログラミング (object-oriented programming)
ここでは命令型プログラミングを紹介。
ちなみに、命令型ってのは要するにフツーのプログラミング方法。色んな変数をいじりながら(状態遷移させながら)、「逐次実行」「繰り返し」「条件分岐」を繰り返してプログラムを書く方法。対義語(?)は関数型のような宣言型プログラミング。
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();