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
IOvalue, instead of trying to apply it to the value wrapped inside theIOvalue.randomListdoes not return a list of values; it returns anIOaction 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
IOaction can produce; you need to use the monad instance to bind the value to an appropriate function.whnf printElementsis one such function; it takes a list and returns anIOaction.Instead of pulling the list out and passing it to
whnf printElements, we "push" the function into anIOvalue using>>=. That operator's type, specialized to theIOmonad, isIn this case, the first
IO avalue is theIO [t]value returned byrandomList.whnf printElementsis thea -> IO bfunction we bind to. The result is a newIOvalue that take the firstIOvalue, pulls out the wrapped value, applies the given function, and returns the result.In other words, the
IOmonad itself takes care of pulling apart the result fromrandomListand 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 singleIOaction.)