Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
FizzBuzz in Haskell [pdf] (files.wordpress.com)
69 points by revskill on Nov 21, 2022 | hide | past | favorite | 38 comments


See also the fastest FizzBuzz written in x86-64+AVX2 Assemby, running at 45GiB/s:

<https://codegolf.stackexchange.com/questions/215216/high-thr...>

<https://github.com/orent/htfizzbuzz/blob/master/fizzbuzz.S>


Discussed one year ago:

https://news.ycombinator.com/item?id=29031488

(1260 points, 256 comments)

p.s. It's actually 55GiB/s, aka 59GB/s :)


That is one of the greatest feats of programming I've ever seen.


How does the Haskell version fare?


This one gets you 0.2 job offers / day.


A few times FizzBuzz appeared on HN, I made this point ...

> "Outputting fizzbuzz should be done by executing the (one and only) piece of code that outputs fizz, followed by the (one and only) piece that outputs buzz. That is because fizzing and buzzing are two separate activities – consider the FizzBuzzHissHowl problem, where hiss and howl are printed for multiples of 7 and 11 respectively. The program design of Exhibit A and B would lead to an explosion of code complexity."

... but always got voted off the island in favor of Exhibit A.

Unclear to me why the canonically correct answer examples for various languages are almost universally mistaken as described there, and yet so fiercely defended!

Perhaps Exhibit C is like Fight Club, to be kept hush hush as a shibboleth for sussing out Principal Engineers?


Here's the resulting Haskell code

    fizzbuzz n = (test 3 "fizz" . test 5 "buzz") id (show n) where
      test d s x = if n `mod` d == 0 then const (s ++ x "") else x

    main = mapM_ (putStrLn . fizzbuzz) [0..100]
you can compile with ghc and run...


Explanation:

If both tests fail, return the 'id' (identity) function which when applied to (show n) will return the number as a string.

If one or both tests succeed, return a 'const' function which will simply return the appropriate string and ignore the (show n).

This example was illuminating. It helped me realize I'm wasting too much time with Haskell.


A minor comment, but I’d reformat this a bit to make its structure clearer:

    fizzbuzz n = go id (show n)
      where
        go = test 3 "fizz" . test 5 "buzz"

        test d s x =
          if n `mod` d == 0 
          then const (s ++ x "")
          else x


> I don't know about Java.

It's very solvable in Java, as we see here: https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpris...


I think a major part of the FizzBuzz test is writing something simple and understandable. Premature/unnecessary optimization isn't a plus, it's a minus. Start with the basic "Exhibit A" for a FizzBuzz.

If a second problem asks you to write something for "FizzBuzzHissHowl", then you can start introducing more code complexity.


I really liked this !

As a novice ( but really interested) in functional programming, I had a bit of troubles with Haskell and eventually didn't find something I could do to toy with it.

This paper is basically what I want to try doing in functional programming : almost write maths, but that does the computation.

It wasn't too complex either !

Can someone point me to other resources in the same genre ?


For the for math-y and proof oriented content, you can look at "The Tao of Functional Programming"

For something more practical, but in PureScript, this e-book has tons of examples and detailed explanations (most concepts translate to Haskell) https://jordanmartinez.github.io/purescript-jordans-referenc...


The Haskell Road to Maths, Logic and Programming by Kees Doats and Jan van Eijck may be of interest to you.

https://staff.fnwi.uva.nl/d.j.n.vaneijck2/HR/


I know this is a "toy" paper, but is enough to reason as to why few use Haskell in production (ignoring the tooling issue). It's pretty gnarly even for a basic problem.

> Functional programmers! Remember higher-order functions!

I didn't realise utilising HoF meant rolling your own interpreter ;).

Pure FP is very interesting, but having to write entirely without side-effects would be a real challenge for me. I use js+ramda[0], we effectively write our services as a `pipe`, you just stick in transforming fns whereever you need to, e.g.:

  const handler = pipe(
    fn1,
    fn2,
    fn3
  )(event)
The underlying implementation of `fn1` for example doesn't need to be written in an fp paradigm, it can be written imperatively. You could then slowly-slowly chop out the imperative functions for fp ones if you really wanted, but IMHO some problems are best solved imperatively.

My advice is instead: "Programmers! Remember to use the right tool for the job!"

[0] https://ramdajs.com/docs/


You're looking at this the wrong way. The paper isn't showing Haskell is gnarly for a basic problem, it's using a basic problem to demonstrate a particular technique that you can use in Haskell. There are plenty of simpler ways to implement this kind of thing in Haskell, and even some that are both simpler and show off some of the more unique features of Haskell. The goal here wasn't "let's find the best way to write fizzbuzz in Haskell", it was "let's show off how to build an interpreter to solve problems, using a small problem everyone is familiar with".

Haskell isn't ill-suited for something like fizzbuzz at all, it's just _also_ suited for things like quickly writing interpreters and solving problems that way when it makes sense.


I find a lot of people don't get pedagogy. They want immediate, authoritative statements on what is good or bad. Haskell isn't really about that. It's about the 10s of equivalent ways to solve every simple problem. That's what makes it fun. And fun is Haskell's secret sauce.


Case in point: it can prompt people to gush about a fizzbuzz implementation.


"10s of equivalent ways to solve every simple problem."

Why doesn't C#, Java, etc have the same problem with perception because they have the same "many ways" to solve problems.

"fun"

brainfuck is fun too and no one uses it.


Because C#, Java, etc are more familiar to most people. People tend to struggle with unfamiliar things.

Haskell is simple even if unfamiliar to you. Brainfuck is complex even if familiar to you.


> Haskell is simple even if unfamiliar to you. Brainfuck is complex even if familiar to you.

I would actually swap these two descriptions. Haskell is complex, because it has many "complications" (in the sense of features). But those complications permit simple programs. Brainfuck is simple, it has few complications (only 8 instructions) but this forces complications into the programs written in it.


Simplicity is not merely measured in the "number of things" you have, it's contextual. Otherwise we'd all be writing in binary representations because base two is the simplest way to communicate information.

Simplicity is also "how many things" it takes to express an idea or do a useful thing.

In many ways, written Chinese is simpler than written English.


We seem to be in violent agreement.


This paper takes a deliberately weird solution to the problem.

FizzBuzz can be done more "normally" in Haskell with similar levels of simplicity as non-FP languages: https://wiki.haskell.org/Fizzbuzz


The paper even gives three normal examples early on, including one similar to the one in your link.

People who miss that are clearly looking hard for some reason to dismiss the work.


That is the FP version of the classic https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpris... . One can overengineer stuff in both FP and OOP.


This looks very clear and straightforward even knowing nothing about Haskell syntax.


I found this to be well above average as an intro to Haskell.


plus you don't even need the first line.


https://stackoverflow.com/a/6957469

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


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.


So, instead of checking twice if the number is divisible by five, you check once but then you check the type of every instruction again. How is that a win?


Yeah it is a bit of a strawman, especially as Exhibit B solves this problem (and an inline function would remove the duplication). However as the mention at the end this isn't a serious performance tuning session, or even a serious answer to FizzBuzz, but a way to introduce some Haskell concepts.


This person can say, "I worked at FB using Haskell".


Ugh. There are languages that encourage this kind of time wasting. Avoid them. Also,

> Exhibit A, in some cases, performs the ‘mod‘ 3 and ‘mod‘ 5 tests more than once

Isn't Haskell a language with controlled side-effects? Compiler ought to see that the same operation is performed twice and factor it out. There are no mutable variables in the scope.


> Compiler ought to see that the same operation is performed twice and factor it out.

Yes but the trouble is when Haskell does optimisations, it's criticised for having unpredictable performance characteristics.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: