您想要活动模式:
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.
如果您不了解第二个示例的工作原理,请发表评论,我会更深入地介绍。
将活动模式组合在一起
由于活动模式只是函数,因此您可以使用标准函数组合将它们连接在一起。好吧,几乎是标准的功能组合。带运算符的普通函数组合>>
意味着“将函数 1 的结果作为函数 2 的输入”。但是在这里,函数 1 和函数 2 都返回Some ()
,但是取一个 int; 您不能将 1 的输出传递给 2 的输入,因为它们不是兼容的类型。但我们想要的实际上是将相同的输入传递给两个函数,并组合它们的输出。
因此,我们将不使用普通的函数组合,而是定义我们自己的函数,该函数采用两个活动模式,Some ()
如果两个模式都匹配输入则返回:
let matchesBoth pattern1 pattern2 x =
match pattern1 x with
| None -> None
| Some _ -> pattern2 x
在我们讨论的时候,让我们定义一个自定义运算符,以便您了解它是如何工作的。此matchesBoth
函数的工作方式与运算符非常相似&&
,因为它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|_|)