Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem when displaying integer arithmetic with a random number in Haskell

Let's say I want to generate a random number in Haskell. To do so, I'll make use of

randomRIO (0, 10)

that generates a number between 0 and 10 for me. It's type is

randomRIO (0,10) :: (Random a, Num a) => IO a

Now, let's say I assign its result to a value k. It's type is IO Integer.

Trying to do usual arithmetic stuff such as k + 2 will yield the following result in Ghci:

<interactive>:1:3:
    No instance for (Num (IO Integer))
      arising from the literal `2'
    Possible fix: add an instance declaration for (Num (IO Integer))
    In the second argument of `(+)', namely `2'
    In the expression: k + 2
    In an equation for `it': it = k + 2

The problem also happens when trying asking Ghci about

[randomRIO (0, 10) | x <- [0..10]]

The error message is a bit cryptic, how can I make use of random numbers in Haskell?

like image 522
devoured elysium Avatar asked Mar 09 '26 09:03

devoured elysium


2 Answers

A value of type IO Integer is not an integer. It's an action that, when performed, will return an integer. The distinction is important. The only way to perform IO actions is to hook them up to main, or type them into GHCi.

So randomRIO (0, 10) is an action, that when performed, returns a random number between 0 and 10. Note that this is not a function, as a function must always return the same result given the same input, although we sometimes call this an impure function.

So the question is, how do you take an action returning an integer and make an action returning an integer plus two? Easy, you can use fmap to combine an action and a pure function transforming its result into a new action.

fmap (+2) $ randomRIO (0, 10)

Control.Monad contains many useful functions for building new actions out of other actions. For your second example, we can use replicateM, which creates an action that, when performed, runs the original action multiple times, collecting the results into a list:

replicateM 10 $ randomRIO (0, 10)

You can also obtain similar results manually using do-notation.

For more information, you should read up on monads, for example in Learn You a Haskell.

like image 77
hammar Avatar answered Mar 10 '26 22:03

hammar


You would best be served by working through a resource like Learn You a Haskell. A very relevant section is here.

like image 21
Anthony Avatar answered Mar 11 '26 00:03

Anthony



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!