All About Monads explains sequence_:
The
sequence_function (notice the underscore) has the same behavior assequencebut does not return a list of results. It is useful when only the side-effects of the monadic computations are important.
Then, looking at TestSequence.hs:
import Control.Monad
f :: String -> IO ()
f x = print x
run :: [String] -> IO ()
run xs = sequence_ . map f $ xs
I can run it:
λ: run ["foo", "bar"]
"foo"
"bar"
Is sequence_ calling unsafePerformIO on each IO () to get the result, i.e. the ()?
And, is sequence_ discouraged? Or is it, for the IO Monad, simply used "at the end of the world" to run a list of IO actions?
No, it is not calling unsafePerformIO on each IO () action. In fact, its type is not even specific to IO:
sequence_ :: (Monad m, Foldable t) => t (m a) -> m ()
In the old libraries, when it was specific to lists (rather than generic over all Foldables), it was implemented in the following perfectly readable way:
sequence_ [] = return ()
sequence_ (x:xs) = x >> sequence_ xs
It is absolutely not discouraged; sequence_ (and its big brother, mapM_) are extremely useful, to the point that it is even one of my motivating examples for why Monads as an abstraction are useful.
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