I'm trying to understand Active Patterns, so I'm playing around with FizzBuzz:
let (|Fizz|_|) i = if i % 3 = 0 then Some Fizz else None
let (|Buzz|_|) i = if i % 5 = 0 then Some Buzz else None
let (|FizzBuzz|_|) i = if i % 5 = 0 && i % 3 = 0 then Some FizzBuzz else None
let findMatch = function
| Some Fizz -> "Fizz"
| Some Buzz -> "Buzz"
| Some FizzBuzz -> "FizzBuzz"
| _ -> ""
let fizzBuzz = seq {for i in 0 .. 100 -> Some i}
|> Seq.map (fun i -> i, findMatch i)
Is this basically the right approach, or is there a better way to use Active Patterns here? Shouldn't I be able to make findMatch
take an int instead of int option?
Daniel's first solution can be simplified, because you don't actually need to define a separate active pattern for FizzBuzz
. The case can be described as both Fizz
and Buzz
matching, which can be nicely expressed in the pattern language:
let findMatch = function
| Fizz & Buzz -> "FizzBuzz"
| Fizz -> "Fizz"
| Buzz -> "Buzz"
| _ -> ""
let fizzBuzz = [ for i in 0 .. 100 -> findMatch i ]
The pattern Fizz & Buzz
matches if both Fizz
and Buzz
match. This relies on the fact that the pattern is matched first, so the order is relevant in this case. I also shortened your last line a little to a style that I prefer and is a bit shorter (but opinions vary).
Alternatively, if you don't want to define too many single-purpose active patterns, you could also write a parameterized active pattern that tests whether an input is divisible by any specified number:
let (|DivisibleBy|_|) by n = if n%by=0 then Some DivisibleBy else None
let findMatch = function
| DivisibleBy 3 & DivisibleBy 5 -> "FizzBuzz"
| DivisibleBy 3 -> "Fizz"
| DivisibleBy 5 -> "Buzz"
| _ -> ""
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With