Iteratively print each integer in a list

Say I have a list of integers l = [1,2]

What I want to print on stdout .

Running print l creates [1,2]

Say I want to print a list without braces

map print l produces

 No instance for (Show (IO ())) arising from a use of `print' Possible fix: add an instance declaration for (Show (IO ())) In a stmt of an interactive GHCi command: print it 

`: t print

 print :: Show a => a -> IO () 

So, while I thought this would work, I went ahead and tried:

 map putStr $ map show l 

Since I suspected that the type mismatch from Integer to String was to blame. This led to the same error message as above.

I understand that I could do something like combining a list into a string, but I would like to avoid this if possible.

What's happening? How can I do this without building a string from list items?

+2
haskell ghc ghci
source share
5 answers

Suppose you are given a list xs :: [a] and a function f :: Monad m => a -> mb . You want to apply the function f to each xs element, getting a list of actions, and then follow the sequence of actions. This is how I would like to build a function, name it mapM , which does this. In the base case, xs = [] is an empty list, and we simply return [] . In the recursive case, xs has the form x : xs . First, we want to apply f to x by specifying the action fx :: mb . Then we want to call mapM recursively on xs . The result of the first step is a value, for example, y ; the result of the second step is a list of values, for example, ys . So, we collect y and ys into a list, and then return them to the monad:

 mapM :: Monad m => (a -> mb) -> [a] -> m [b] mapM f [] = return [] mapM f (x : xs) = fx >>= \y -> mapM f ys >>= \ys -> return (y : ys) 

Now we can map a function of type print , which returns the action in the IO monad, on the list of printable values: mapM print [1..10] does just that for a list of integers from one to ten. However, there is a problem: we do not particularly care about collecting the results of printing operations; we are primarily concerned about their side effects. Instead of returning y : ys we simply return () .

 mapM_ :: Monad m => (a -> mb) ->[a] -> m () mapM_ f [] = return () mapM_ f (x : xs) = fx >> mapM_ f xs 

Note that mapM and mapM_ can be defined without explicit recursion using the sequence and sequence_ functions from the standard library that exactly match their names. If you look at the source code for mapM and mapM_ in Control.Monad , you will see that they are implemented in this way.

+2
source share

The problem is

 map :: (a -> b) -> [a] -> [b] 

So, we are done with [IO ()] . This is pure value, IO action list. Actually nothing is printed. Instead we want

 mapM_ :: (a -> IO ()) -> [a] -> IO () 

The naming convention *M means that it works on monads, and *_ means that we throw away the value. This is similar to a map, except that it sequentially performs each action with >> to return an IO action.

As an example, mapM_ print [1..10] will print each element on a new line.

+6
source share

Everything in Haskell is very heavily typed, including code to execute IO!

When you write print [1, 2] , this is just a convenient wrapper for putStrLn (show [1, 2]) , where show is a function that turns an object (Showable) into a string. print itself does nothing (in the sense of a side effect of do), but it produces an IO() action, which is similar to the unrun mini-program (if you excuse the sloppy language), which is not 't "run" at the time of its creation, but which can be transferred for subsequent execution. You can check the type in ghci

 > :t print [1, 2] print [1, 2]::IO() 

It's just an object like IO () .... You can throw it away right now and nothing will ever happen. Rather, if you use this object in main , I / O code, side effects and that’s it.

When you map several putStrLn (or print ) functions in a list, you still get an object whose type you can view in ghci

 > :t map print [1, 2] map print [1, 2]::[IO()] 

As before, it is just an object that you can go through and will not do anything by itself. But unlike the previous one, the type is incorrect for use in main, which the IO () object expects. To use it, you need to convert it to this type.

There are many ways to do this conversion ... One of the ways that I like is the sequence function.

 sequence $ map print [1, 2] 

which takes a list of I / O operations (that is, mini-programs with side effects if you forgive a sloppy language) and combines them sequentially, as with an I / O operation. Only this code will do what you want.


As jozefg noted, although sequence works, sequence_ is the best choice here .... A sequence not only concatenates the material in an I / O action, but also puts the return values ​​in a list .... Since the print return value is IO (), the new the return value becomes a useless list () (in IO). :)

+2
source share

Using the lens library:

 [1,2,3] ^! each . act print 
+1
source share

You can also write your own function:

 Prelude> let l = [1,2] Prelude> let f [] = return (); f (x:xs) = do print x; f xs Prelude> fl 1 2 
0
source share

All Articles