I tried googling this but I couldn't find a collection of words that guided me to what I am trying to do.
I am trying to solve Project Euler Problem 54, and I have this rather ridiculous function:
let evaluate hand =
if isRoyalFlush hand then 9
elif isStraightFlush hand then 8
elif isFour hand then 7
elif isFullHouse hand then 6
elif isFlush hand then 5
elif isStraight hand then 4
elif isThree hand then 3
elif isTwoPair hand then 2
elif isPair hand then 1
else 0
All the isSomething keywords are functions that take a string array and return a Boolean. Is there a more elegant way of doing this using pattern matching ?
This doesn't work:
match true with
| isRoyalFlush hand -> 9
| isStraightFlush hand -> 8
// .. etc
I am looking for something like this:
match hand with
| isRoyalFlush -> 9
| isStraightFlush -> 8
// .. etc
I remember seeing something like that at one point but I can't remember where or how to find it.
You want active patterns:
Or better, pull out all that common code into a simple active-pattern builder:
If you don't understand how that second example works, leave a comment and I'll go into more depth.
Composing active patterns together
Since active patterns are just functions, you can use standard function composition to join them together. Well, almost standard function composition. Normal function composition with the
>>operator means "take the result of function 1, and use it as the input to function 2". But here, function 1 and function 2 both returnSome (), but take an int; you can't pass the output of 1 into the input of 2, since they aren't compatible types. But what we want is actually to pass the same input to both functions, and combine their output.So instead of using normal function composition, we'll define our own function that takes two active patterns, and returns
Some ()if both patterns match the input:And while we're at it, let's define a custom operator so you can see how that works. This
matchesBothfunction works very much like the&&operator, in that it will returnSome ()only if both patterns would returnSome ()for any given inputx. We shouldn't overload the&&operator to take a different type, so let's create a custom operator that looks like&&, but reminds us that it's combining two active patterns. If our operator looks like|&&|, that should be perfect. So let's create it:That's it! Now we can do something like:
Or, for your example: