I have such code:
foldl (\a x -> a ++ (f x)) [] list
All seems to be ok, but (f x) :: IO [String]
, and (++)
gives an error ([String] != IO [String]).
How to define empty IO[String] list? I can't make clean (f x).
The combinator you want here is probably
Prelude Control.Monad> :t foldM
foldM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a
and with that
foldM (\a x -> fmap (a++) (f x)) [] list
to run the actions f x
in sequence and accumulate the [String]
s they produce.
In:
foldl (\a x -> a ++ (f x)) [] list
you're trying to do a ++ f x
but f x :: IO [String]
, so it's not working. Let's see if we can work out what's going on.
You mean for x
to come from your list
, so you'll be applying f
in turn to each of the elements of the list, and they each give you a [String]
and you want to concatenate them together as you go along.
We'll use mapM :: Monad m => (a -> m b) -> [a] -> m [b]
, which maps a function over a list then sequences the monad operations together into one, combining the outputs into a list.
concatMapM :: (a -> IO [String]) -> [a] -> IO [String]
concatMapM f list = fmap concat (mapM f list)
Here I've used fmap
to apply the pure function concat
to the result of the IO operation.
You could test it out using
fileLines :: FilePath -> IO [String]
fileLines filename = fmap lines (readFile filename)
*Main> concatMapM fileLines ["test1.txt","test2.txt"]
["This is test1.txt","It has two lines.","This is test2.txt","It has two lines too."]
This way is better than trying to foldl, because concat
works more efficiently than foldl (++)
. To check this out for yourself, compare these for speed:
*Main> writeFile "test3.txt" $ foldl (++) [] (map show [1..10000])
*Main> writeFile "test3.txt" $ foldr (++) [] (map show [1..10000])
The trouble is that foldl
does (((a++b)++c)++d)++e
so runs through the list a
four times - it runs through it first as it adds b
, then it runs through a
and b
as it adds c
, then it runs through a
, b
and c
as it adds d
, then runs through all four of them as it adds e
. This is a big waste of effort.
foldr
does a ++ (b ++ (c ++ (d ++ e)))
so runs through each list once - d
then c
then b
then a
. concat
is a foldr
, which is much better for this list operation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With