Why can't you print a print to a list in Haskell?
I checked this post before doing this, but this post doesn't really explain why it doesn't work.
foo :: (Num a, Show a) => a -> IO ()
foo 0 = print "Was zero"
foo x = print x
foo 2 -- prints 2
foo 5 -- prints 5
map foo [0..10] :: [IO ()] -- Doesn't print out numbers.
Edit:
bar 0 = foo 0
bar n = do
foo n
bar (n - 1)
I understand why this returns [IO ()]
, but I don't understand why printing does not occur when this list is created. At least I expect we will see the first print call due to lazy evaluation.
In the process of creating this list, why isn't there a "side effect" of printing on the screen? Is the function foo
actually not injected when applied to every item in the list? If the calls print
are evaluated to get IO ()
to create the list, why isn't the side effect happening?
source to share
map foo [0..10]
will definitely build a list of values IO ()
, but constructing a value IO ()
does not IO
. You probably know this intuitively: if we have a global IO ()
and nothing refers to it, it will fail:
sayHello :: IO ()
sayHello = putStrLn "hello"
You can attribute this to laziness; after all, unless sayHello
referenced, nothing ever forces it to evaluate. But then that doesn't do anything either:
main = sayHello `seq` return ()
Here we, of course, evaluate sayHello
, but only evaluate IO ()
.
Which does IO
something to do when you compose it into another IO
(for example main
) and it runs, and only then does it do something:
main = sayHello
I should note that the GHCi tarnishes a little. GHCi has some special interactions with IO
: if the general expression you enter in the prompt yields IO
, it will execute it and show the result. Otherwise, it just displays the result. But this is just an interactive feature; in real Haskell code, you cannot have IO ()
and expect it to ()
magically turn out .
source to share
The only way to trigger an action IO
is to assign it main
. Evaluating actions IO
doesn't trigger them.
If you want to call print
on a list of values, you have to do two things:
First: use mapM_
to create an action IO
that print
each value:
mapM_ print [1..3] :: IO ()
Second, assign to this expression main
:
main = mapM_ print [1..3]
If you leave the second step (assign it to something other than main
), nothing happens.
source to share