さて、関数型言語には大体ある(と思ってる)パターンマッチについてやってみます。といっても私が経験してる関数型言語はHaskellとF#だけなので、全部の言語にあるかどうかは良く知りません。まぁC#でパターンマッチに該当するものって何?っていうとswitch文がそれにあたります。ただし、C#のswitch文がお粗末でかわいそうに見えてくるくらい強力です。
書き方は以下のようになります。
match 評価したい式 with | パターン -> 結果式 | パターン -> 結果式 | パターン -> 結果式 | パターン -> 結果式
というわけで簡単な例を書いてみます。とりあえず普通のswitch文相当の簡単なものから。
let f x = // xの値で結果がを変えるswitch文みたいなもの match x with | 0 -> "Zero" | 1 -> "One" | 2 -> "Two" | _ -> "Many" // 実行してみよう printfn "f 0 = %s" <| f 0 printfn "f 1 = %s" <| f 1 printfn "f 2 = %s" <| f 2 printfn "f 3 = %s" <| f 3
上記のプログラムでは0 1 2 _がパターンマッチの所にあたります。このように数字を指定するのは、定数パターンと呼ばれています。数字以外にも"hoge"のような文字列や1.0などのような実数、Color.Redのような値も使えます。
上記の実行結果は以下のようになります。
f 0 = Zero f 1 = One f 2 = Two f 3 = Many
定数だけだと、C#とかのswitchと大差ありません。ちょっと前に使ったoption型を使ってみようと思います。option型はSomeとNoneを持つので、それをパターンのところに書きます。早速プログラム例を見てみましょう。
let f x = // Someだったら値を取得してNoneだったら0を返す match x with | Some v -> v | None -> 0 printfn "%A" <| f (Some 10) printfn "%A" <| f None
こうやってoption型の結果を受け取ったらmatchでやるのがスマートだと思われます。
その他にタプルもパターンマッチ出来ます。
let f x = match x with | (0, 0) -> "Zero" | (1, 0) -> "One" | (0, _) -> "Hoge" | _ -> "Other" printfn "%s" <| f (0, 0) printfn "%s" <| f (1, 0) printfn "%s" <| f (0, 100) printfn "%s" <| f (2, 2)
実行結果は以下のようになります。_はパターンマッチの何にでもマッチする便利な子なんです。
Zero One Hoge Other
他には、パターンマッチにorやandといった条件も指定できます。
// orの例 let f x = match x with | 1 | 2 | 3 -> "小さい" | 4 | 5 | 6 -> "普通" | 7 | 8 | 9 -> "大きい" | _ -> "その他" printfn "%s" <| f -1 printfn "%s" <| f 1 printfn "%s" <| f 5 printfn "%s" <| f 9
andの場合は&で指定したりします。上記のプログラムを実行すると以下のような結果になります。
その他 小さい 普通 大きい
今更FizzBuzz
ちょっと前に、Twitterでigetaさんが示してくれた例でパターンマッチの強力さを思い知ったのでコードを紹介したいと思います。こういう風に使えるとは…と思いました。
let fb x = match (x%3, x%5) with |(0, 0) -> "FizzBuzz" |(0, _) -> "Fizz" |(_, 0) -> "Buzz" | _ -> string x [1..100] |> List.map fb |> List.iter (printf "%s ")
実行結果
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fiz z 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz 41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz Fizz 52 53 Fizz Buzz 56 Fizz 58 59 Fi zzBuzz 61 62 Fizz 64 Buzz Fizz 67 68 Fizz Buzz 71 Fizz 73 74 FizzBuzz 76 77 Fizz 79 Buzz Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzz
なかなか、3で割った余りと5で割った余りのタプルでパターンマッチするという発想は出てきませんでした。ということでパターンマッチについては以上です!
過去記事
- 手軽なスクリプト言語としてのF#
- 手軽なスクリプト言語としてのF# その2
- 手軽なスクリプト言語としてのF# その3
- 手軽なスクリプト言語としてのF# その4
- 手軽なスクリプト言語としてのF# その5
- 手軽なスクリプト言語としてのF# その6
- 手軽なスクリプト言語としてのF# その7
- 手軽なスクリプト言語としてのF# その8「レコード」
- 手軽なスクリプト言語としてのF# その9「クラス」
- 手軽なスクリプト言語としてのF# その10「継承・アブストラクトクラス」
- 手軽なスクリプト言語としてのF# その11「インターフェースと演算子のオーバーロード」
- 手軽なスクリプト言語としてのF# その12「ラムダ式とイベント」
- 手軽なスクリプト言語としてのF# その13「オブジェクト初期化子みたいなの」
- 手軽なスクリプト言語としてのF# その14「合成演算子とパイプ演算子」
- 手軽なスクリプト言語としてのF# その15「WPFしてみた」
- 手軽なスクリプト言語としてのF# その16「総称型 ジェネリック」
- 手軽なスクリプト言語としてのF# その17「リスト」
- 手軽なスクリプト言語としてのF# その18「オプション型」
- 手軽なスクリプト言語としてのF# その19「参照型よりオプション型って安全?」