There is a surprisingly large number of convenience functions that aren’t in the Prelude or standard libraries, but perhaps should be. I wouldn’t fret too much over reimplementing a few if you find them useful.
Noting that altF
is equivalent to liftA2 (<|>)
, you might write it more like this:
till :: (Monad m, Alternative m) => (a -> m a) -> (a -> m b) -> a -> m b
-- To do f till p is to first do f; then either p, or f till p.
f `till` p = f >=> (<|>) <$> p <*> f `till` p
And noting that (Monad m, Alternative m)
is much the same as MonadPlus m
, you can simplify the type a bit:
till :: MonadPlus m => (a -> m a) -> (a -> m b) -> a -> m b
f `till` p = f >=> mplus <$> p <*> f `till` p
There is a similar function called untilM
in Control.Monad.Loops which uses a Bool
predicate, and a LoopT
transformer exists for arbitrary looping in Control.Monad.Trans.Loop. But no, this particular function doesn’t seem to be famous yet.