Hacker News new | ask | show | jobs
by Waterluvian 1301 days ago
https://stackoverflow.com/a/6957469

This seems very elegant and clean and I don’t know the slightest bit of Haskell other than “MONADS!!!”

2 comments

I don't like that solution very much because of the 4 cases, or generally n*2 cases if there are n tokens. My favorite Haskell solution uses monoids (specificaly the Monoid instance of Maybe String) and is quite natural in Haskell but would take some explanation for non-Haskellers.

My version looks like the below. I didn't originate the approach but I like this spelling. It won't make total sense to non-Haskellers though.

    {-# LANGUAGE MonadComprehensions #-}
    import           Data.Maybe
    import           Data.Monoid

    fizz :: Int -> String
    fizz n = fromMaybe (show n) $ f 3 "Fizz" <> f 5 "Buzz"
      where
        f :: Int -> String -> Maybe String
        f d msg = [msg | n`rem`d == 0]

    main = mapM_ putStrLn [fizz n | n <- [1..100]]
This extends in an obvious way to FizzBuzzHissHowl, lets the Monoid instance manage concatenating the special tokens together while remembering if any of the rules have matched, and uses a monad comprehension on the Maybe monad to cleanly lift the token into the Maybe monad if the number is a multiple of whatever. The type annotation on f is added to make it a little bit clearer what is going on.

The use of monoids and the monad comprehension may be slightly flashy, but the use of Maybe to remember whether a rule has triggered is second nature in Haskell.

This is not too dissimilar to the final solution outlined in the essay, but is much more readable, in my opinion, due to its use of mappend over Maybe Strings instead of implementing the same sort of compositionality using regular function composition. Very elegant!
The one you linked is close to how you'd write this in idiomatic Haskell. The paper is describing a particular technique, and using FizzBuzz as an example problem, not suggesting that the technique is a good way to solve FizzBuzz.