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?

+3


source to share


4 answers


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 .

+9


source


If the calls print

are evaluated to get IO ()

to create the list, why isn't the side effect happening?



Since type expression evaluation IO ()

has no side effects. In fact, evaluating an expression of any type has no side effects.

+2


source


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.

+2


source


A monad IO

requires something like IO a

. You have [IO ()]

which is a list of I / O operations. Instead, you can use mapM

to make a monadic map. mapM f

is equivalent sequence . map f

.

-1


source







All Articles