haskellrandomiohaskell-lensgloss

Couldn't match type ‘IO’ with ‘[]’


I wrote a function to generate two random numbers, which I then pass to a different function to use them there. The code for this is:

randomIntInRange :: (Int, Int, Int, Int) -> Board
randomIntInRange (min,max,min2,max2) = do r <- randomRIO (min, max)
                                          r2 <- randomRIO (min2, max2)
                                          randomCherryPosition (r, r2)

And the function this function calls in its 'do' block is:

randomCherryPosition :: (Int, Int) -> Board
randomCherryPosition (x, y) = initialBoard & element y . element x .~ C

Where initialBoard is a list of lists and C is a predefined data type. I am using lens to change values inside the list. Running this gives me the error:

Couldn't match type ‘IO’ with ‘[]’
      Expected type: [Int]
        Actual type: IO Int

for both r and r2 lines. I have absolutely no idea what is going on here, or what i'm doing wrong, so I would greatly appreciate any help.


Solution

  • randomRIO has type IO Int, not Int. As long as you use any IO functions, your surrounding function must also be in IO:

    randomIntInRange :: (Int, Int, Int, Int) -> IO Board
    randomIntInRange (min,max,min2,max2) = do r <- randomRIO (min, max)
                                              r2 <- randomRIO (min2, max2)
                                              pure $ randomCherryPosition (r, r2)
    

    randomRIO is not a pure function. It returns a different value every time. Haskell bans such functions. There are numerous benefits that come from banning such functions, which I'm going to go into here. But you can still have such function if you wrap it in IO. The type IO Int means "it's a program that, when executed, will produce an Int". So when you call randomRIO (min, max), it returns you not an Int, but a program, which you can then execute to get an Int. You do the execution via the do notation with left arrow, but the result of that would also be a similar program.