Kevin Meredith
Kevin Meredith

Reputation: 41919

Understanding `sequence_`

All About Monads explains sequence_:

The sequence_ function (notice the underscore) has the same behavior as sequence but 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?

Upvotes: 4

Views: 2563

Answers (1)

Daniel Wagner
Daniel Wagner

Reputation: 153102

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.

Upvotes: 11

Related Questions