haskellmonadsmonadplus

MonadPlus and forever - what is the relation?


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.


Solution

  • 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.