So lately I have a list of strings, and need to independently go over each one and perform some IO
function.
So basically what I have is this:
sepp2k and solrize are right to recommend mapM_
. But, in the spirit of teaching you to fish instead of giving you a fish, here's something you can try in the future:
(String -> IO ()) -> [String] -> IO ()
.String
with a
to get (a -> IO ()) -> [a] -> IO ()
, and search for that.Now the third result of the second search is mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
, which is exactly what you want. (The first answer, closeFdWith :: (Fd -> IO ()) -> Fd -> IO ()
is not a relevant result; the second, traverse_ :: (Foldable t, Applicative f) => (a -> f b) -> t a -> f ()
is relevant but a bit more complicated to understand and use.)
First, easy improvement:
goOverList' :: [String] -> IO ()
goOverList' [] = return ()
goOverList' (x:xs) = do
putStrLn x
goOverList' xs
The base case for recursion should be the empty list: in that case, you simply return the IO action return ()
which does nothing. When you have one or more elements, you print it and continue with the rest of the list, simple as that.
The same exact thing is achievable in a way more compact definition with mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
: it is the same as the regular map
, except that it works with monadic actions. Instead of returning the collection of results m [b]
like the regular mapM
would do, it throws it away. It works just fine for you in this case, as you're are only interested in printing out the elements of he list.
goOverList'' :: [String] -> IO ()
goOverList'' = mapM_ putStrLn
In order to be even more general, we could rely on print :: Show a => a -> IO ()
instead of putStrLn
and accept in input every list of "showable" items:
goOverList''' :: (Show a) => [a] -> IO ()
goOverList''' = mapM_ print
data T = One | Two | Three deriving (Show)
main = do
let myList = [One, Two, Three]
goOverList''' myList
Your goOverList
function is almost equivalent to mapM_ putStrLn
. (Just almost because mapM_
also works with the empty list while your function does not).
mapM is a function that applies a function of type a -> IO b
¹ to each item in a list of a
s and gives you back an IO
² with a list of b
s. mapM_
is the same as mapM
except that it doesn't store the results in a list (which doesn't make sense for actions that return ()
like putStrLn
does).
¹ Actually it's more general than that: The function has type a -> m b
where Monad m
, but in this case m
is IO
.
² Again it's actually m.
Your goOverList
function can be written mapM_ putStrLn
where mapM_
is a function in the standard Prelude.
You can also simplify your own implementation:
goOverList :: [String] -> IO ()
goOverList [] = return ()
goOverList (x:xs) = do
putStrLn x
goOverList xs