Comment

Comment by drostie

I'm probably guilty of this, as a guy who is learning Haskell. FizzBuzz can be just

    main = putStrLn $ unlines $ map fizzer [1..100] where
        fizzer n | n % 15 == 0  = "FizzBuzz"
                 | n %  3 == 0  = "Fizz"
                 | n %  5 == 0  = "Buzz"
                 | otherwise    = show n
but I think the first time I tried to solve it in Haskell I had something more like:

    import Data.Monoid (Monoid, mconcat)
    import Data.Maybe (catMaybes)

    specialcases :: (Monoid y) => [x -> Maybe y] -> x -> Either x y
    specialcases rules x = case catMaybes (map ($ x) rules) of
        [] -> Left x
        xs -> Right (mconcat xs)

    ifDivBy :: Integer -> x -> Integer -> Maybe x
    ifDivBy n x m = if m `mod` n == 0 then Just x
                                        else Nothing

    main = putStrLn $ unlines $ strings where
        strings = map (either show id) cases
        fizzer = specialcases [ifDivBy 3 "Fizz", ifDivBy 5 "Buzz"]
        cases = map fizzer [1..100]
This is basically thinking about an imperative problem the "wrong way around": starting with the logical distinction between "we're in a special case" and "we're in the normal case" and building everything else around it. (Also, who is ever going to use that Monoid instance? Replace `id` with `concat` and you can just remove `Data.Monoid` altogether -- and if you really wanted it generic, taking an explicit `y -> y -> y` and using `foldl1` would be more flexible anyway.)
parent drostie 11 years ago

Discussion

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton