Question: Given a function which produces a random integer in the range 1 to 5, write a function which produces a random integer in the range 1 to 7.

I’m going to slightly modify the question. First, I want to deal with integers starting with 0, so the ranges will be 0 to 4 and 0 to 6. Second, random numbers are a little tricky in Haskell, since they violate referential integrity. My answers could be written monadically to handle this, but instead I will write functions that take an infinite list (or lists) of integers, assumed to be uniformly random and in the range of 0 to 4. Here’s my first answer:

> random_0_to_6_take_0=head

head is the haskell function that returns the first member of a list. Since the first member is given as a random integer in the range 0 to 4, it is also a random number in the range 0 to 6. But that’s not the intent of this question. Let’s get a little closer to meeting that intent.

> random_0_to_6_take_1ns=(sum$take6ns)`div`4

take returns the first n (in this case 6) members of a list. sum adds them up. So, this function sums up 6 random numbers to get 0-24, and integer divides the result by 4 to get a number from 0 to 6.

Again, this answer matches the specification of the question, but likely not the intent. This will produce a random integer between 0 and 6, with 5 and 6 as possible outputs, but the distribution of the outputs won’t be uniform. They’ll be biased towards the middle, just as two 6-sided dice are most likely to add up to 7 when rolled. Additionally, this function will produce 6 only once in 15625 calls (on average). Let’s fix that:

zipWith traverses two lists memberwise, mapping each pair of members using the given function. Since x and y are uniformly distributed between 0 and 4, x + (5 * y) is uniformly distributed between 0 and 24. find returns the first member satisfying the given predicate, which nets us an integer, uniformly distributed between 0 and 20. Dividing by 3 and truncating gives an integer, uniformly distributed between 0 and 6. Mission accomplished! Now to make it work.