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...
精彩评论