1. 7
  1.  

  2. 5

    In contrast with every practical language I’ve used, Haskell does not provide an “easy” method of acquiring a random value.

    It’s the same method, Haskell just gives you the option of not using mutation.

    One can get “easy” random values in the IO monad, (randomIO :: IO a) but that’s no fun.

    This does literally what every other language’s PRNG does and makes the previous statement incorrect.

    1. 2

      Thanks for the feedback! Maybe I should have been more clear and less cheeky? I was hoping that the rest of that section would remove the tension introduced by the statements that you quoted.

      The implicit argument is that Haskell enforces purity, and reading/updating a global PRNG is an IO operation par excellence. By making this explicit, or by reifing this fact, as I like to think, Haskell removes the “easy” way of injecting indeterminism into your pure computations. So getting a random value in your pure function a -> b is not easy – in fact it’s impossible. Easy, in scare quotes, was meant as: “Easy to use, hard to reason about”.

      The enforced purity involves a bit more work up front, but produces code that is clearer and more composable (thus testable), but I’m not going to preach to the choir on this point.

      Aside

      To be fair, other languages do offer you the option of reifiying the randomness game (take a source, update it, pass it along to the next computation), but none offer the monadic machinery that relieves the programmer of having to tag along that random source.

      Erlang, for example, gives you two options, the “easy” one:

      uniform() -> float()
      Returns a random float uniformly distributed between 0.0 and 1.0, updating the state in the process dictionary.

      and the pure one:

      uniform_s(State0) -> {float(), State1}
      State0 = State1 = ran()
      Given a state, uniform_s/1returns a random float uniformly distributed between 0.0 and 1.0, and a new state.

      But nothing prevents you from using the first one in any nominally-pure algorithm. You can’t have reliable tests for code that uses randomness, unless you specifically use the second variant, threading that state through the entire computation.

      Guess which is more popular with working programmers? The below is from a mid-sized Erlang project and includes its dependencies:

      $ ack 'random:uniform\(' | wc -l
      26
      
      $ ack 'random:uniform_s\(' | wc -l
      5
      
      1. 0

        Haskell removes the “easy” way of injecting indeterminism into your pure computations

        This is a contradiction in terms and isn’t true for many reasons. It doesn’t make anything difficult unless you’ve just begun learning to use IO in Haskell.

        So getting a random value in your pure function a -> b is not easy – in fact it’s impossible.

        This is like complaining that it’s impossible to drink bleach because the aliens steal the bleach out of your summer cottage. If you want to get a pseudo-random value without performing IO, ask for either a generator or the value in your function arguments or make the type a -> IO b. This is not an actual problem.

        in fact it’s impossible.

        Indicator #4 you decided to rip on a language you don’t know very well in a blog post you decided to post to lobsters. I realize your audience doesn’t know any better, but please, Haskellers see this stuff every week. I just want one week’s break. At least until the book is done.

        please

        \section[Comment Exercise}

        \subsection{German Tank Problem}

        Wait how many indicators were there in my comment? Where there only 4? More than four? What if he’s not using a simple incrementing system for keeping count?

        Expect this in the quiz.

        1. 2

          In case you think I’m lying about it not being impossible

          Not something you’d ever want to actually do, since there’s absolutely nothing wrong with IO. Be kind to other programmers (including you, 2 weeks later), be explicit!