アクティブなパターンが必要です:
let (|IsRoyalFlush|_|) hand =
if isRoyalFlush hand then Some () else None
let (|IsStraightFlush|_|) hand =
if isStraightFlush hand then Some() else None
// etc.
match hand with
| IsRoyalFlush -> 9
| IsStraightFlush -> 8
// etc.
または、すべての共通コードを単純なアクティブ パターン ビルダーに引き出します。
let toActivePattern pred x =
if pred x then Some () else None
let (|IsRoyalFlush|_|) = isRoyalFlush |> toActivePattern
let (|IsStraightFlush|_|) = isStraightFlush |> toActivePattern
// etc.
match hand with
| IsRoyalFlush -> 9
| IsStraightFlush -> 8
// etc.
2 番目の例の仕組みがわからない場合は、コメントを残してください。詳しく説明します。
アクティブなパターンを一緒に構成する
アクティブなパターンは単なる関数であるため、標準的な関数構成を使用してそれらを結合できます。まあ、ほぼ標準的な機能構成。>>
演算子を使用した通常の関数合成は、 「関数 1 の結果を関数 2 の入力として使用する」ことを意味します。ただし、ここでは、関数 1 と関数 2 の両方が を返しSome ()
ますが、int を取ります。互換性のある型ではないため、1 の出力を 2 の入力に渡すことはできません。しかし、実際には両方の関数に同じ入力を渡し、それらの出力を結合する必要があります。
Some ()
したがって、通常の関数構成を使用する代わりに、2 つのアクティブなパターンを受け取り、両方のパターンが入力に一致した場合に戻る独自の関数を定義します。
let matchesBoth pattern1 pattern2 x =
match pattern1 x with
| None -> None
| Some _ -> pattern2 x
では、カスタム オペレータを定義して、それがどのように機能するかを見てみましょう。この関数は、指定された入力に対して両方のパターンが返される場合にのみ返されるという点で、演算子とmatchesBoth
非常によく似ています。オペレータをオーバーロードして別の型を取るべきではないので、 のようなカスタム オペレータを作成しましょう。ただし、2 つのアクティブなパターンを結合していることを思い出してください。演算子が のように見える場合、それは完璧なはずです。それでは、それを作成しましょう:&&
Some ()
Some ()
x
&&
&&
|&&|
let (|&&|) = matchesBoth
それでおしまい!これで、次のようなことができます。
let (|Div3|_|) n =
if n % 3 = 0 then Some () else None
let (|Div5|_|) n =
if n % 5 = 0 then Some () else None
let (|Div15|_|) = (|Div3|_|) |&&| (|Div5|_|)
let fizzbuzz n =
match n with
| Div15 -> "FizzBuzz"
| Div5 -> "Buzz"
| Div3 -> "Fizz"
| _ -> string n
fizzbuzz 30 // Result: "FizzBuzz"
fizzbuzz 31 // Result: "31"
または、あなたの例では:
let (|IsStraightFlush|_|) = (|IsStraight|_|) |&&| (|IsFlush|_|)