-
-
Save jbrains/2a29465457bddcca0c45 to your computer and use it in GitHub Desktop.
-- Thanks to @kimwallmark for teaching me `maybe` and showing me how a single lookup. | |
-- I had the brilliant idea of using `snd`, even though I dislike the name. :) | |
fizzbuzz :: Integer -> String | |
fizzbuzz n = maybe (show n) snd $ classify n | |
where | |
classify n = find (\(m, _) -> n `mod` m == 0) [(15, "Fizzbuzz"), (5, "Buzz"), (3, "Fizz")] |
Interesting use of fold: it feels similar to using it to compute max
of an arbitrary list, using the "accumulator" to represent "highest so far". In this case, the accumulator represents "the best answer so far".
As you say, though, this relies on the sequence of the items in table
, and in a way that I didn't easily see. While I find this too clever, it might become convenient during refactoring to know that foldr
can behave like find
in certain situations.
I would prefer to do this with findWithDefault
, which the maybe
version implements.
Actually, find is a better solution in this case I would think (I'm no expert either, not even close). But for academic purposes, I like to do everything with a fold because... well, because everything manipulating a list can be a fold. Helps me understand the rest.
Find can be written with a fold. In reality it uses filter
though. Filter could also be implemented with fold, but it uses pattern matching and recursion. Someone clever than me must know why this is a better choice :)
Your code with the find
implementation has the exact same gotcha as mine does though, just less obvious. find
is just listToMaybe . filter
. Filter will return a list filtered by a predicate, and listToMaybe turns [1, 2, 3] into Just 1 (and [] into Nothing). The 2 and 3 go into the trash.
Have you already seen http://www.haskell.org/haskellwiki/Haskell_Quiz/FizzBuzz ? There are several quite different approaches there...
A variant on the guards version is to use a pattern match. I adapted this from the Scala version at http://rosettacode.org/wiki/FizzBuzz#Scala
fizzbuzz :: Integer -> String
fizzbuzz n = case map (mod n) [3,5] of [0,0]->"FizzBuzz"; [0,_]->"Fizz"; [_,0]->"Buzz"; _->show n
(Naturally, this can be formatted sensibly rather than as a gratuitous one-liner! Although I now realize that the canonical guard version can actually be packed into a smaller one-liner, if one is that way inclined ;-)
Thanks again, @jni-. I'll have to read that more carefully. :)