Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looking for generalisation of the `if p x then x else empty` construct

I have a couple of snippets which feel like they're doing the same thing, but I'm not entirely convinced there is a generalised construct to handle them both. In one place, I have

ensure :: (String -> Bool) -> String -> String
ensure p x =
    if p x then
        x
    else
        ""

This might in use look something like

ensure (/= "kim") "alex"    -- returns "alex"
ensure (/= "kim") "kim"     -- returns ""

in another, I have the very similar

ensure :: (a -> Bool) -> Maybe a -> Maybe a
ensure p maybeX = do
    x <- maybeX
    if p x then
        Just x
    else
        Nothing

This would instead look something like

ensure even 6     -- returns Just 6
ensure even 11    -- returns Nothing

Both are checking whether a value is correct according to some predicate, and if it's not they're returning a default "empty"-looking value. There is a slight difference though – which means the second function could be rewritten as

ensure :: (Maybe a -> Bool) -> Maybe a -> Maybe a
ensure p maybeX =
    if p x then
        x
    else
        Nothing

to make them more similar, putting the responsibility of "unwrapping" the Maybe on the predicate. With this new definition, both functions would fall under

ensure :: Alternative f => (f a -> Bool) -> f a -> f a
ensure p x =
    bool x empty (p x)

So, my question is,

Does this bool x empty (p x) exist in some form so I don't have to implement this function myself? The problem with inlining bool x empty (p x) is that in my case, both p and x are quite long.

like image 370
kqr Avatar asked Dec 04 '15 13:12

kqr


1 Answers

Below are suggestions from the comments. One using Monoid, by 9000:

ensure :: Monoid a => (a -> Bool) -> a -> a
ensure p a = if p a then a else mempty

Another using MonadPlus, by user3237465:

ensure :: MonadPlus m => (a -> Bool) -> a -> m a
ensure p = mfilter p . return

And a variant of the second one that only requires Alternative, by Daniel Wagner:

ensure :: Alternative f => (a -> Bool) -> a -> f a
ensure p x = x <$ guard (p x)
like image 87
2 revs, 2 users 70% Avatar answered Nov 07 '22 03:11

2 revs, 2 users 70%