I find a lot of things I jigger together on my own that seem at all useful actually have a standard implementation that I just didn't know about, so was curious if anybody could say they've seen this type of thing used before:
It takes a monadic function and will fold it until a predicate is chosen by alternative then it returns the result of the predicate:
until :: (Monad m, Alternative m) => (a -> m a) -> (a -> m c) -> a -> m c
f `until` p = \a -> (f >=> (p `altF` (until f p))) a
where f1 `altF` f2 = \a -> f1 a <|> f2 a
I realize the name is a prelude collision, I'll probably name it something else but thought I'd first see if there's already a similar piece of functionality in a standard library I just don't know about..
Also I guess I'm curious if the compositional alternative I wrote is defined elsewhere or if any of this bit of functionality seems misguided to begin with. But the crux of my question is, is this implemented elsewhere or is something very similar implemented elsewhere perhaps
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With