开发者

Shorter way to write this code

The following pattern appears very frequently in Haskell c开发者_如何学编程ode. Is there a shorter way to write it?

if pred x
then Just x
else Nothing


You're looking for mfilter in Control.Monad:

mfilter :: MonadPlus m => (a -> Bool) -> m a -> m a

-- mfilter odd (Just 1) == Just 1
-- mfilter odd (Just 2) == Nothing

Note that if the condition doesn't depend on the content of the MonadPlus, you can write instead:

"foo" <$ guard (odd 3) -- Just "foo"
"foo" <$ guard (odd 4) -- Nothing


Hm... You are looking for a combinator that takes an a, a function a -> Bool and returns a Maybe a. Stop! Hoogle time. There is no complete match, but find is quite close:

find :: (a -> Bool) -> [a] -> Maybe a

I doubt that you can actually find your function somewhere. But why not define it by yourself?

ifMaybe :: (a -> Bool) -> a -> Maybe a
ifMaybe f a | f a = Just a
ifMaybe _ _       = Nothing


You can use guard to achieve this behavior:

guard (pred x) >> return x

This is such a generally useful behavior that I've even defined ensure in my own little suite of code for one-offs (everybody has such a thing, right? ;-):

ensure p x = guard (p x) >> return x


Use:

(?:) (5>2) (Just 5,Nothing)

from Data.Bool.HT.


f pred x = if pred x then Just x else Nothing

Given the above definition, you can simply write:

f pred x

Of course this is no different than Daniel Wagner's ensure or FUZxxl's ifMaybe. But it's name is simply f, making it the shortest, and it's definition is precisely the code you gave, making it the most easily proven correct. ;)

Some ghci, just for fun

ghci> let f pred x = if pred x then Just x else Nothing
ghci> f (5>) 2
Just 2
ghci> f (5>) 6
Nothing

If you couldn't tell, this isn't a very serious answer. The others are a bit more insightful, but I couldn't resist the tongue-in-cheek response to "make this code shorter".


Usually I'm a big fan of very generic code, but I actually find this exact function useful often enough, specialized to Maybe, that I keep it around instead of using guard, mfilter, and the like.

The name I use for it is justIf, and I'd typically use it for doing things like this:

∀x. x ⊢ import Data.List
∀x. x ⊢ unfoldr (justIf (not . null . snd) . splitAt 3) [1..11]
[[1,2,3],[4,5,6],[7,8,9]]

Basically, stuff where some sort of element-wise filtering or checking needs to be done in a compound expression, so Maybe is used to indicate the result of the predicate.

For the specialized version like this, there really isn't much you can do to make it shorter. It's already pretty simple. There's a fine line between being concise, and just golfing your code for character count, and for something this simple I wouldn't really worry about trying to "improve" it...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜