Everything in Haskell is very strongly typed, including code to perform IO!
When you write print [1, 2]
, this is just a convenience wrapper for putStrLn (show [1, 2])
, where show is a function that turns a (Show'able) object into a string. print
itself doesn't do anything (in the side effect sense of do), but it outputs an IO()
action, which is sort of like a mini unrun "program" (if you excuse the sloppy language), which isn't "run" at its creation time, but which can be passed around for later execution. You can verify the type in ghci
> :t print [1, 2]
print [1, 2]::IO()
This is just an object of type IO ()
.... You could throw this away right now and nothing would ever happen. More likely, if you use this object in main
, the IO code will run, side effects and all.
When you map multiple putStrLn
(or print
) functions onto a list, you still get an object whose type you can view in ghci
> :t map print [1, 2]
map print [1, 2]::[IO()]
Like before, this is just an object that you can pass around, and by itself it will not do anything. But unlike before, the type is incorrect for usage in main, which expects an IO() object. In order to use it, you need to convert it to this type.
There are many ways to do this conversion.... One way that I like is the sequence
function.
sequence $ map print [1, 2]
which takes a list of IO actions (ie- mini "programs" with side effects, if you will forgive the sloppy language), and sequences them together as on IO action. This code alone will now do what you want.
As jozefg pointed out, although sequence
works, sequence_
is a better choice here....
Sequence not only concatinates the stuff in the IO action, but also puts the return values in a list.... Since print's return value is IO(), the new return value becomes a useless list of ()'s (in IO). :)