Every wanted to roll the dice in Haskell? Let’s say you have a data type like
1 2 |
|
How do you generate a random Number
value? There are several ways to do it, usually in an IO
context, obviously. In order to use it in a
common monad transformer stack, the primitives of the MonadRandom
type class come to my mind. So it would be most convenient to get a
random value using getRandom
. Anyway, as much fun as rolling the dice is, let’s derive a solution working for all bounded Enums.
Anyway, import Control.Monad.Random as we want to use getRandom
of the MonadRandom
class which looks like:
1 2 3 4 5 6 7 8 |
|
Shortly, randomR
needs to be able to provide a random Number
value in the specified interval, given a random number generator. So the idea is about mapping the Enum values to Int
values
and deriving a random Enum value from a randomly generated number.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
While we still used the explicit Number
interval values in 1), we get a more general solution in 2) using the fact that we had auto-derived an instance of Bounded
for Number
and thus have minBound
and maxBound
at our disposal.
At last, we can generate a random Number
value:
1 2 |
|
Anyway, our generated Number
values are uniformly distributed, every value occurs with equal probability. What if you want to tamper with the die at little, e.g.
when your opponent throws the dice they should not get a Six
quite so often. You could do that providing a respective Random
instance for a newtype wrapper:
1 2 3 4 5 6 7 8 9 10 11 |
|
Your rollDice
function then looks so inconspicuous, your opponent might not even notice:
1 2 3 4 5 6 7 8 9 |
|
They might actually think that they are just unlucky:
1 2 3 4 |
|
You can find the source here.