I've got the following function:
lines' :: [IO String]
lines' = getLine : lines'
I was hoping I could just use all the mighty list functions on this list, like filter etc. But my knowledge about the IO monad in haskell is improvable.
The list-of-io_stuff-concept convinced me after using Rx for C#.
Is there any way to do what I want in haskell ? Something like:
ten_lines :: [IO String]
ten_lines = take 10 lines'
proc_lines :: [IO String]
proc_lines = [ (l, length l) | l <- lines' ]
Thanks!
There are a whole bunch of normal list functions modified to work with monads in Control.Monad
. Of particular interest to your question:
sequence :: Monad m => [m a] -> m [a]
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
filterM :: Monad m => (a -> m Bool) -> [a] -> m [a]
foldM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a
(sequence
and mapM
are actually exported by the prelude and available by default.)
For example, let's take a look at the type of your take 10 lines'
example:
Prelude Control.Monad> :t take 10 lines'
take 10 lines' :: [IO String]
We want to turn this [IO String]
into a single IO [String]
action. This is exactly what sequence
does! We can tell this by the type signature. So:
sequence $ take 10 lines'
will do what you want.
Most of these functions also have a version ending in _
, like sequence_
. This has exactly the same effect as the normal function except it throws away the result, returning ()
instead. That is, sequence_ :: [m a] -> m ()
. This is a good choice whenever you don't actually care about the result for two reasons: it's more explicit about your intentions and the performance can be better.
So if you wanted to print 10 lines rather than get them, you would write something like this:
printLines = putStrLn "foo" : printLines
main = sequence_ $ take 10 printLines
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