アクティブパターン
F#には「アクティブパターン」と呼ばれる特殊なパターンマッチングがあります。これは、パターンを動的に解析したり検出したりできるものです。通常のパターンと同様に、呼び出し側から見ると、マッチングと出力が1つのステップに統合されています。
以下は、アクティブパターンを使用して文字列をintまたはboolに解析する例です。
// アクティブパターンを作成let (|Int|_|) str = match System.Int32.TryParse(str) with | (true,int) -> Some(int) | _ -> None
// アクティブパターンを作成let (|Bool|_|) str = match System.Boolean.TryParse(str) with | (true,bool) -> Some(bool) | _ -> None
今はアクティブパターンを定義するために使用される複雑な構文について心配する必要はありません。これはただの例で、アクティブパターンがどのように使われるかを見てもらうためのものです。
これらのパターンが設定されると、通常の「match..with」式の一部として使用できます。
// パターンを呼び出す関数を作成let testParse str = match str with | Int i -> printfn "この値はint '%i'です" i | Bool b -> printfn "この値はbool '%b'です" b | _ -> printfn "値 '%s' は他の何かです" str
// テストtestParse "12"testParse "true"testParse "abc"
呼び出し側から見ると、Int
やBool
とのマッチングは透過的です。裏で解析が行われているにもかかわらず、それが見えないようになっています。
同様の例として、正規表現でアクティブパターンを使用し、正規表現パターンとマッチングすると同時に、マッチした値を1つのステップで返すこともできます。
// アクティブパターンを作成open System.Text.RegularExpressionslet (|FirstRegexGroup|_|) pattern input = let m = Regex.Match(input,pattern) if (m.Success) then Some m.Groups.[1].Value else None
ここでも、このパターンが設定されると、通常のマッチ式の一部として透過的に使用できます。
// パターンを呼び出す関数を作成let testRegex str = match str with | FirstRegexGroup "https?://(.*?)/(.*)" host -> printfn "この値はURLで、ホストは %s です" host | FirstRegexGroup ".*?@(.*)" host -> printfn "この値はメールアドレスで、ホストは %s です" host | _ -> printfn "値 '%s' は他の何かです" str
// テストtestRegex "https://google.com/test"testRegex "alice@hotmail.com"
そして楽しみのために、もう1つ例を挙げましょう。有名なFizzBuzzチャレンジをアクティブパターンを使って書いたものです。
// アクティブパターンを設定let (|MultOf3|_|) i = if i % 3 = 0 then Some MultOf3 else Nonelet (|MultOf5|_|) i = if i % 5 = 0 then Some MultOf5 else None
// メイン関数let fizzBuzz i = match i with | MultOf3 & MultOf5 -> printf "FizzBuzz, " | MultOf3 -> printf "Fizz, " | MultOf5 -> printf "Buzz, " | _ -> printf "%i, " i
// テスト[1..20] |> List.iter fizzBuzz