早いもので23回目になりました。
今回はアクティブパターンというものを紹介してみようと思います。こいつも使いこなすとなかなか便利そうなので、ちょっと本気だして習得しようと思いました。
さて、アクティブパターンとはなんぞや?ということですが、一言でいうと入力を仕分けしてくれる関数みたいなものだと理解しました。
ある値に対して仕分けを行うというとmatchが、そのものずばりな動きをしてくれるものだと思うのですが、このアクティブパターンはmatch式で使ったりします。
とりあえず、定義の仕方を見てみようと思います。定義は以下のようになります。
// Complete active patternと言われてるもの let (|識別子1|識別子2| ... |) 引数 = 式 // Partial active patternと言われてるもの let (|識別子1|識別子2| ... |_|) 引数 = 式
関数の定義の関数名のところが、(| |)で囲まれて|で区切られています。因みに(| ... |)のことをバナナクリップと呼ぶらしいです。雑学でした。
これは式の部分で、識別子として定義したものを戻り値とすることで入力に対して、それがどんな値かということをラベルづけするようなイメージです。Partial active patternのほうは、Option型を使って戻り値を返すのが特徴で仕分けしきれなかったケースをNoneで表します。
では、とりあえず単純な例として0〜33をLow、 34〜66をMiddle、66〜をHightと仕分けするアクティブパターンを定義してみようと思います。
// 入力を3パターンに仕分けする let (|Low|Middle|Hight|) x = match x with | x when x < 33 -> Low | x when x < 66 -> Middle | _ -> Hight
何気にはじめて使う構文を使ってますが、match式のwhenの後に条件式を書くと、その条件式がtrueの時に右側の式が評価されるという動きをするものです。まぁif文と似たような雰囲気ですね。こんな風にバナナクリップの中で定義した値を入力値に対して返します。
では、実際に使ってみようと思います。今回はLowの時に「うわぁ小さい・・・」、Middleの時に「ふ〜ん普通ね」、Hightの時に「うわっおっき〜い」と表示する関数を作ってみます。
let printState x = match x with | Low -> printfn "うわぁ小さい・・・" | Middle -> printfn "ふ〜ん普通ね" | Hight -> printfn "うわっおっき〜い" // 使ってみる printState -1 printState 0 printState 23 printState 50 printState 100 printState 200
実行すると以下のような結果になります。
うわぁ小さい・・・ うわぁ小さい・・・ うわぁ小さい・・・ ふ〜ん普通ね うわっおっき〜い うわっおっき〜い
このように、すっきりとパターンマッチが書けるようになります。素敵ですね。
次に、Partial active patternのほうを見てみます。これは、仕分けしきれないものをNoneで返すというところ以外はComplete active patternと同じです。実際に定義してみます。今回は0より小さくて100より大きいものは範囲外としてみました。
let (|OutOfRange|_|) x = if x > 100 || x < 0 then Some OutOfRange else None
今回はSome OutOfRangeという戻り値を返していますが、ここは「Some 任意の値」を返すことも出来ます。このPartial active patternはpartialという名前が示す通り複数のアクティブパターンと組み合わせて使うことが出来ます。試しに、さっきのやつと組み合わせて使ってみようと思います。0〜100の範囲に入らないものは「えっ・・・規格外すぎる」と表示してみようと思います。
let printState x = match x with // このように他のアクティブパターンと組み合わせて使える | OutOfRange -> printfn "えっ・・・規格外すぎる" // OutOfRangeに当てはまらないと下に流れていく | Low -> printfn "うわぁ小さい・・・" | Middle -> printfn "ふ〜ん普通ね" | Hight -> printfn "うわっおっき〜い" // 使ってみる printState -1 printState 0 printState 23 printState 50 printState 100 printState 200
実行してみましょう。
えっ・・・規格外すぎる うわぁ小さい・・・ うわぁ小さい・・・ ふ〜ん普通ね うわっおっき〜い えっ・・・規格外すぎる
ばっちり0より小さいものと100より大きいものが規格外と表示されてます。このようにちょっと複雑な条件になりがちなパターンマッチを部品化して組み合わせて使えるという点でアクティブパターンは夢ひろがると思います。
あとは、入力値された値をばらすのにも使えたりします。
open System // DateTime型を年月日にばらすアクティブパターン let (|Date|) (d : DateTime) = (d.Year, d.Month, d.Day) // 適当な日付を作って let date = DateTime.ParseExact("2011/02/11", "yyyy/MM/dd", null) // パターンマッチで値をばらせる match date with |Date (y, m, d) -> printfn "match %d %d %d" y m d // 関数チックにもつかえる let y, m, d = (|Date|) date printfn "関数チックにばらす %d %d %d" y m d
実行結果
match 2011 2 11 関数チックにばらす 2011 2 11
なかなか、使いでのよさそうな奴だと思いました。因みにF#に無くて不満だった正規表現のパターンマッチですがMSDNのサンプルにそのものズバリの答えが書いてありました。
MSDNのサンプルの劣化版ですが、簡単にしたものを以下に示します。
ポイントは2つ以上の引数を持つアクティブパターンは、1つの引数を受け取るアクティブパターンになるように引数をバインドして使うという所です。今回の例だとRegexは2つの引数を受け取るので1つ引数を指定して使っています。そして、パターンマッチでひっかかった結果が変数sに入るという寸法です。
open System.Text.RegularExpressions // patternにマッチした部分を返す let (|Regex|_|) pattern str = let r = Regex.Match(str, pattern) if r.Success then Some r.Value else None let printMatch input = match input with | Regex "太郎" s -> printfn "マッチしたのは %s" s | Regex ".の." s -> printfn "マッチしたのは %s" s | _ -> printfn "マッチしなかった" printMatch "田中 太郎がいけめん" printMatch "あれはてたこうやでのデスマッチ" printMatch "田中 一郎が消えた"
実行すると、以下のようになります。正規表現でひっかかった場所だけが表示されてるのがわかります。
マッチしたのは 太郎 マッチしたのは でのデ マッチしなかった
以上、アクティブパターンでした。
過去記事
- 手軽なスクリプト言語としての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「参照型よりオプション型って安全?」
- 手軽なスクリプト言語としてのF# その20「パターンマッチ」
- 手軽なスクリプト言語としてのF# その21「再帰とループ」
- 手軽なスクリプト言語としてのF# その22「列挙型」