I'm learning F#, and have challenged myself to write a good functional implementation of FizzBuzzWoof. (The difference from "standard" FizzBuzz is that any number that either is divisible by or contains the appropriate number must be replaced by the appropriate string of text: 3 = Fizz, 5 = Buzz, 7 = Woof. Also, the strings must be printed in that order.)
I wrote a version using partial matching that I'm quite happy with, except for the one darn mutable
Boolean in there that makes it feel less than functional to me. Is there a way I can get rid of that mutable
Boolean, and still have clean code?
My attempt so far:
module FizzBuzzWoof =
let isDivisibleBy a b = (a % b) = 0
let contains a b = a.ToString().Contains(b.ToString())
let fizzBuzzWoofMatcher n = fun i ->
if isDivisibleBy i n then Some ()
elif contains i n then Some ()
else None
let (|Fizz|_|) i = fizzBuzzWoofMatcher 3
let (|Buzz|_|) i = fizzBuzzWoofMatcher 5
let (|Woof|_|) i = fizzBuzzWoofMatcher 7
open FizzBuzzWoof
let runme () =
for i = 1 to 100 do
let mutable matched = false // Want to eliminate this
match i with
| Fizz () -> printf "Fizz"; matched <- true
| _ -> ()
match i with
| Buzz () -> printf "Buzz"; matched <- true
| _ -> ()
match i with
| Woof () -> printf "Woof"; matched <- true
| _ -> ()
if matched
then
printfn ""
else
printfn "%d" i
runme()
I did come up with the idea of replacing the final if matched
with another match
expression as follows:
match i with
| Fizz () -> printfn ""
| Buzz () -> printfn ""
| Woof () -> printfn ""
| _ -> printfn "%d" i
And this would work, but it runs the match functions an extra time. In this case this is absolutely fine since they're all quite fast, but what if I have a match function that takes a long time? Is there a way to run each match function just once, yet still avoid the use of mutable
?