Question

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

Which I want to print to stdout.

Doing print l produces [1,2]

Say I want to print the list without the 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 a type mismatch from Integer to String was to blame. This produced the same error message as above.

I realize that I could do something like concatenating the list into a string, but I would like to avoid that if possible.

What's going on? How can I do this without constructing a string from the elements of the List?

Was it helpful?

Solution 2

Suppose you're given a list xs :: [a] and function f :: Monad m => a -> m b. You want to apply the function f to each element of xs, yielding a list of actions, then sequence these actions. Here is how I would go about constructing a function, call it mapM, that does this. In the base case, xs = [] is the empty list, and we simply return []. In the recursive case, xs has the form x : xs. First, we want to apply f to x, giving the action f x :: m b. Next, we want recursively call mapM on xs. The result of performing the first step is a value, say y; the result of performing the second step is a list of values, say ys. So we collect y and ys into a list, then return them in the monad:

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

Now we can map a function like print, which returns an action in the IO monad, over a list of values to print: mapM print [1..10] does precisely this for the list of integers from one through ten. There is a problem, however: we aren't particularly concerned about collecting the results of printing operations; we're primarily concerned about their side effects. Instead of returning y : ys, we simply return ().

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

Note that mapM and mapM_ can be defined without explicit recursion using the sequence and sequence_ functions from the standard library, which do precisely what their names imply. If you look at the source code for mapM and mapM_ in Control.Monad, you will see them implemented that way.

OTHER TIPS

The problem is that

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

So we end up with [IO ()]. This is a pure value, a list of IO actions. It won't actually print anything. Instead we want

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

The naming convention *M means that it operates over monads and *_ means we throw away the value. This is like map except it sequences each action with >> to return an IO action.

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

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). :)

Using the lens library:

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

You might write your own function, too:

Prelude> let l = [1,2]

Prelude> let f [] = return (); f (x:xs) = do print x; f xs

Prelude> f l 
1
2
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top