Search code examples
haskellrandommonadsdo-notation

How do I deal with the error "No instance for (Control.Monad.IO.Class.MonadIO [])"?


Good evening everybody! This is a question concerning Haskell. I want to get x random elements from a list by using a function.

The problem I get is that when I try to use random numbers, with randomRIO. I get the error message:

No instance for (Control.Monad.IO.Class.MonadIO [])
        arising from a use of `randomRIO'

This error message suddenly goes away when i use print or return. But I dont want to use print, and return messes up the output to a nested list [[a]] instead of [a].

Does any of you have a tip on what I can do to extract x random elements from the list, in the form of a list?

The type would be something like this. xRanElems :: [a] -> Int -> [a] where the second Int is an accumulator but I got that covered.

xRanElems xs n = do
  r <- randomRIO (0, n)
  xRanElems2 xs n r

where n is just length xs - 1

xRanElems2 xs n r = (xs !! r) : (xRanElems (xsWithOutSelectedElem xs r) (n-1))

Thankful for any input!


Solution

  • The following typechecks:

    import System.Random
    
    xRanElems  :: [a] -> Int -> IO [a]
    xRanElems xs n = do
      -- randomRIO :: Random t 
      --           => (t, t) -> IO    t
      r <- randomRIO  (0, n)  -- r :: Int
      xRanElems2  xs      n      r    
    
    xRanElems2 :: [a] -> Int -> Int -> IO [a]
    xRanElems2 xs n r = 
       let (a,b:c) = splitAt r xs 
       in 
         fmap (b :)                --     [a] ->    [a]
              (xRanElems           --  IO [a] -> IO [a]
                   (a++c) (n-1))
    

    Trying to run it, e.g. with xRanElems [1..3] 2, reveals that it loops forever.

    This is because you need to provide the base case in xRanElems to stop the recursion, e.g. returning [] when n <= 0.

    The above code also contains an off-by-1 error which you're invited to fix.