I am new to Haskell and really having trouble with the whole IO thing.
I am trying to find out how long it takes to traverse a list in haskell. I wanted to generate a list of random numbers and pass it as a parameter to a function so that I can print each element of the list. I am using CRITERION package for the benchmark. Here is the code:
{-# LANGUAGE OverloadedStrings #-}
import System.Random
import Control.Exception
import Criterion.Main
printElements [] = return ()
printElements (x:xs) = do print(x)
printElements xs
randomList 0 = return []
randomList n = do
x <- randomRIO (1,100)
xs <- randomList (n-1)
return (x:xs)
main = defaultMain [
bgroup "printElements" [ bench "[1,2,3]" $ whnf printElements (randomList 10)
, bench "[4,5,6]" $ whnf printElements [4,5,6,4,2,5]
, bench "[7,8,9]" $ whnf printElements [7,8,9,2,3,4]
, bench "[10,11,12]" $ whnf printElements [10,11, 12,4,5]
]
]
Error when I run the code:
listtraversal.hs:18:67:
Couldn't match expected type ‘[a0]’ with actual type ‘IO [t0]’
In the second argument of ‘whnf’, namely ‘(randomList 10)’
In the second argument of ‘($)’, namely
‘whnf printElements (randomList 10)’
Put briefly, you need to bind your function to the
IO
value, instead of trying to apply it to the value wrapped inside theIO
value.randomList
does not return a list of values; it returns anIO
action that, when executed, can produce a list of values. Ignoring the various constraints induced by the implementation, the type isAs such, you can't directly work with the list of values that the
IO
action can produce; you need to use the monad instance to bind the value to an appropriate function.whnf printElements
is one such function; it takes a list and returns anIO
action.Instead of pulling the list out and passing it to
whnf printElements
, we "push" the function into anIO
value using>>=
. That operator's type, specialized to theIO
monad, isIn this case, the first
IO a
value is theIO [t]
value returned byrandomList
.whnf printElements
is thea -> IO b
function we bind to. The result is a newIO
value that take the firstIO
value, pulls out the wrapped value, applies the given function, and returns the result.In other words, the
IO
monad itself takes care of pulling apart the result fromrandomList
and applying your function to it, rather than you doing it explicitly.(You might have noticed that I've said that
>>=
binds a value to a function and vice versa. It is perhaps more accurate to say that>>=
binds them together into a singleIO
action.)