以下模式在Haskell代码中经常出现。是否有更短的编写方式?
if pred x
then Just x
else Nothing
以下模式在Haskell代码中经常出现。是否有更短的编写方式?
if pred x
then Just x
else Nothing
你正在寻找在Control.Monad
中的mfilter
:
mfilter :: MonadPlus m => (a -> Bool) -> m a -> m a
-- mfilter odd (Just 1) == Just 1
-- mfilter odd (Just 2) == Nothing
请注意,如果条件不依赖于 MonadPlus
内容,您可以写成:
"foo" <$ guard (odd 3) -- Just "foo"
"foo" <$ guard (odd 4) -- Nothing
mfilter
重写 OP 的问题可能更糟,即:mfilter pred (Just x)
。 - mb14嗯……您正在寻找一个组合器,它需要一个 a
、一个函数 a -> Bool
,并返回一个 Maybe a
。停!Hoogle 时间。没有完全匹配,但是 find
还是相当接近的:
find :: (a -> Bool) -> [a] -> Maybe a
我怀疑你可能找不到你需要的函数,但为什么不自己定义一个呢?
ifMaybe :: (a -> Bool) -> a -> Maybe a
ifMaybe f a | f a = Just a
ifMaybe _ _ = Nothing
find
函数,你可以编写ifMaybe = (. return) . find
。如果用mfilter
代替find
,就可以让它在任何MonadPlus
上运行。 - hammarMonadPlus m => (a -> Bool) -> a -> m a
。如果为真,则结果将是 return x
,否则将是 mzero
。 - hammarmfilter
,是第四个搜索结果。 - Dan Burton使用:
(?:) (5>2) (Just 5,Nothing)
来自Data.Bool.HT。
(5 > 2) ?: (Just 5, Nothing)
。 - Dan Burtonif
/then
/else
之上提供了什么,你仍然不必要地重复了“5”的术语,并且不得不提到“Nothing”。相比之下,“mfilter”解决方案更加优秀。 - Tom Crockettutility-ht
иҪҜ件еҢ…пјҢжӮЁеҸҜд»ҘдҪҝз”ЁtoMaybe
иҖҢдёҚжҳҜ(?:)
=> toMaybe (pred x) x
гҖӮ - mb14guard
来实现这个功能:guard (pred x) >> return x
这是一种非常有用的行为,我甚至在我的代码库中定义了ensure
以供一次性使用(每个人都有这样的东西,对吧?;-):
ensure p x = guard (p x) >> return x
ensure p x = x <$ guard (p x)
,其中<$
来自于Control.Applicative
。稍微更具有指向性: ensure p = ap (<$) (guard . p)
:) - Ben Millwoodguard
已经要求MonadPlus
,所以您仍然无法在非单子应用程序上使用您的ensure
。 - Daniel WagnerAlternative
,但这可能不值得。然而,<$
仍然更可爱。 - Ben Millwoodf pred x = if pred x then Just x else Nothing
根据上述定义,您可以简单地编写:
f pred x
当然,这与Daniel Wagner的ensure
或FUZxxl的ifMaybe
没有什么不同。但它的名称只是f
,使它成为最短的,并且它的定义恰好是您提供的代码,使其最容易被证明正确。;)
一些ghci,只是为了好玩
ghci> let f pred x = if pred x then Just x else Nothing
ghci> f (5>) 2
Just 2
ghci> f (5>) 6
Nothing
如果你还没发现,这不是一个非常严肃的回答。其他人的回答更有见地,但我无法抵制“让这段代码更短”的玩笑回应。
Maybe
类型时非常有用,因此我会保留它,而不是使用guard
、mfilter
等等。justIf
,我通常会用它来做这样的事情:∀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]]
基本上,这是一些需要在复合表达式中进行某种元素级过滤或检查的东西,因此使用Maybe
来指示谓词的结果。
对于像这样的专业版本,你真的没有太多可以做的来使它更短。它已经非常简单了。在简洁和仅仅为了字符计数而压缩代码之间有一条细微的界限,对于这么简单的东西,我不会真的担心试图“改进”它...
λ>
的普及启发了我改变我的,我猜当时这似乎是个好主意? - C. A. McCann
monadplus
中的Control.Monad.Plus
提供了一个名为partial
的函数来实现这一点。更通用的方法是使用bool empty . pure <*> id
。 - dfeuer