前回の補足。
前回、パラメタライズドアクティブパターンに触れた際に、パラメタライズドはパーシャルアクティブパターンに対してしか行えない、と書いたが、実はそうではなかった。
詳しくは、
前回の投稿にのぶひささんからコメント頂いたとおり。
識別子をひとつ持つアクティブパターンにおいては、複数の引数をとりつつ、普通の関数のように某かの値を返すようにしておき、この戻り値を含めたパターンマッチを行うことで、パラメタライズドが可能であった。
そこで実習のために、前回同様、指定の範囲内に収まっている数値かどうかを判定・パターンマッチする、パラメタライズドされたアクティブパターン ― ただし非パーシャル ― を書いてみよう。
まずは、アクティブパターンとして識別子をひとつだけ持つ、(|Between|) を下記のとおり定義する。
>let (|Between|) b e n = b <= n && n <= e;;
見てのとおり、このアクティブパターンは bool 値を返す。
すなわち、n が b 以上 e 以下であれば true、そうでなければ false が返るわけだ。
このパラメタライズドされたアクティブパターンを使って、パターンマッチを記述するには次のとおり。
>let TestC = fun x ->
> match x with
> |
Between 10 100 true -> printfn "%d is between 10 and 100." x
> |_ -> printfn "unmatch.";;
赤い部分が、パラメータ b と e にそれぞれ 10 と 100 を指定して完成させたアクティブパターンで、青い部分がその戻り値にマッチする。
すなわち、"Between 10 100" というアクティブパターンを引数 x に適用したときに戻り値が true となる場合にマッチするのが上記記述のガード条件の第一行となるわけだ。
これで、
>TestC 11;;
11 is between 10 and 100.
val it : unit = ()
>TestC 234;;
unmatch.
val it : unit = ()
となり、無事期待どおりの挙動となっていることが確認できる。
なんだか、アクティブパターンに関しては、はじめに入門した "普通の(?)" アクティブパターンに始まり、パーシャルやパラメタライズドなどが絡み合って、少々理解が混乱気味で表層的ではある。
アクティブパターンは "逆適用" である、といったあたりに理解へのヒントがあるのだろうか?
とはいえ、習うより慣れろ、という側面もあるので、このまま Fizz-Buzz 問題の解決へ向けて先へ進みます。
誤りのご指摘は例によって大歓迎。