Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell IO Int and Int

I recently started to learn Haskell. I'm trying to write a program that pick a random element of array:

import System.Random

randomInt :: (Int, Int) -> IO Int
randomInt range = randomRIO range :: IO Int

choseRandom :: [a] -> a
choseRandom list = 
    length list
    >>=
        (\l -> randomInt(0,l-1))
        >>=
            (\num -> (list !! num))

main :: IO ()
main = undefined

and I get the following error:

Build FAILED

C:\Users\User\Haskell\Real\src\Main.hs: line 7, column 9:
  Couldn't match expected type `IO Int' with actual type `Int'

    In the return type of a call of `length'

    In the first argument of `(>>=)', namely `length list'

    In the first argument of `(>>=)', namely

      `length list >>= (\ l -> randomInt (0, l - 1))'

what I'm doing wrong? It's hard for me to deal monads for first times

like image 345
Sergey Konkin Avatar asked Nov 30 '22 11:11

Sergey Konkin


2 Answers

It's hard for me to deal monads for first times

Yes, and you make it harder by avoiding syntactic support. Just write it thus:

choseRandom list = do
   let l = length list
   num <- randomInt(0,l-1)
   return (list !! num)

Doesn't this look much better?

Now to the point: the randomRIO function, as their type indicates, uses some global state (probably the system timer). Hence you can use results from RandomRIO only in the IO Monad.

An alternative would be to initialize a random generator in the main function, and pass this generator down to pure functions that need "random" values.

like image 44
Ingo Avatar answered Dec 02 '22 01:12

Ingo


Since you're using IO inside choseRandom you need to change the type signature:

choseRandom :: [a] -> IO a

secondly, you don't need to use >>= to get the length of the list. >>= has type

Monad m => m a -> (a -> m b) -> m b

The type of length is [a] -> Int, so the type of length list is Int, which is not a monad.

You can calculate it directly when calling randomInt:

choseRandom :: [a] -> IO a
choseRandom list = 
    randomInt(0, length list) >>= (\num -> return (list !! num))

which is the same as

choseRandom :: [a] -> IO a
choseRandom list = fmap (\num -> (list !! num)) (randomInt(0, length list))
like image 102
Lee Avatar answered Dec 02 '22 01:12

Lee