Proposal: add two more Applicative and Monad adapters

We currently offer liftA, liftM, liftM2, and ap to implement Functor and Applicative methods in terms of Applicative and Monad ones. But there are a couple other functions in that general vein that are missing. I propose that we should add at least replaceA, and perhaps also beforeM. -- (<$) = replaceA -- This may be better than the default if there is -- an optimized definition of *> (which may be -- based on an optimized >>). replaceA :: Applicative f => a -> f x -> f a replaceA a fa = fa *> pure a -- (<*) = beforeM -- This may be better than the default if there is -- an optimized definition of <$, or if <$ is defined as -- replaceA and *> is optimized. beforeM :: Monad f => f a -> f x -> f a beforeM fa fx = fa >>= \a -> a <$ fx Why a <$ fx and not fx >> pure a? Because <$ could be implemented specially, and is unlikely to be implemented by hand using <* if there isn't a custom <*.

Also worth considering:
manyM :: (Alternative f, Monad f) => f a -> f [a]
manyM v = many_v
where
many_v = do
ma <- optional v
case ma of
Nothing -> pure []
Just a -> liftA2 (:) a many_v
someM :: (Alternative f, Monad f) => f a -> f [a]
someM v = liftA2 (:) v (manyM v)
Unlike the default definitions, these bound backtracking when (<|>)
represents that.
On Sat, Aug 11, 2018, 1:19 PM David Feuer
We currently offer liftA, liftM, liftM2, and ap to implement Functor and Applicative methods in terms of Applicative and Monad ones. But there are a couple other functions in that general vein that are missing. I propose that we should add at least replaceA, and perhaps also beforeM.
-- (<$) = replaceA -- This may be better than the default if there is -- an optimized definition of *> (which may be -- based on an optimized >>). replaceA :: Applicative f => a -> f x -> f a replaceA a fa = fa *> pure a
-- (<*) = beforeM -- This may be better than the default if there is -- an optimized definition of <$, or if <$ is defined as -- replaceA and *> is optimized. beforeM :: Monad f => f a -> f x -> f a beforeM fa fx = fa >>= \a -> a <$ fx
Why a <$ fx and not fx >> pure a? Because <$ could be implemented specially, and is unlikely to be implemented by hand using <* if there isn't a custom <*.
participants (1)
-
David Feuer