Home > other >  MonadPlus and forever - what is the relation?
MonadPlus and forever - what is the relation?

Time:06-02

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.

CodePudding user response:

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.

CodePudding user response:

One may naively assume that forever m just goes on forever:

forever m = m >> forever m
          = m >> m >> forever m
          = m >> m >> m >> ...  -- forever

But the comment mentions that there are ways to break the loop, and mzero is a concise example, that demonstrates the situation equationally rather than by thinking about exceptions operationally. mzero satisfies mzero >> w = mzero for all w, so that:

forever mzero = mzero >> forever mzero
              = mzero

The point is that the choice of monad makes forever much more versatile than a mere while (true) loop in imperative languages.

  • Related