I see here
-- Note that "forever" isn't necessarily non-terminating.
-- If the action is in a @'MonadPlus'@ and short-circuits after some number of iterations.
-- then @'forever'@ actually returns `mzero`, effectively short-circuiting its caller.
To be honest I don't understand this note. Do they mean that it is possible to break forever
with MonadPlus
, for instance - IO Bool
? Let's say, IO False
will break it...
From one point of view IO
is MonadPlus
too. Maybe I must wrap my IO Bool
in something else to achieve the possibility to break forever
with IO Bool
and MonadPlus
? What does the note mean at all?
Sure, I can break it with exception or to implement own forever
but my interest is about this strange note.
You can look at how forever
is implemented:
forever :: Applicative f => f a -> f b -> f b
forever a = let a' = a *> a' in a'
The documentation of (*>)
says that it "sequence actions, discarding the value of the first argument". It basically is a (>>)
for Applicatives instead of Monads.
So if you look at how forever
is implemented you'll see that it basically is expanded to:
forever a = a *> a *> a *> ...
As the forever
description says, if the Applicative has some short-circuiting behaviour it can still terminate and not evaluate the infinite sequence of actions:
ghci> forever $ Nothing
Nothing
ghci> forever $ Just 1
-- infinite loop trying to evaluate Just 1 *> Just 1 *> Just 1 *> ...
That is because (Nothing *> _) = Nothing
what follows the (*>)
is not even evaluated, so Nothing *> Nothing *> Nothing *> ...
short-circuits to Nothing
without having to evaluate the infinite list of actions.