【问题标题】:Shorter way to write this code编写此代码的更短方法
【发布时间】:2011-11-19 04:55:02
【问题描述】:

以下模式在 Haskell 代码中经常出现。有没有更短的写法?

if pred x
then Just x
else Nothing

【问题讨论】:

  • 也许你可以发布一些上下文代码来展示它是如何常见的?可能有一种方法可以重写正在使用它的代码......
  • As Petr Pudlák indicates, Control.Monad.Plus from monadplus 提供了一个 partial 函数来做到这一点。更通用的是bool empty . pure <*> id

标签: haskell if-statement combinators maybe


【解决方案1】:

你正在寻找mfilter in Control.Monad:

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)
【解决方案2】:

嗯...您正在寻找一个组合子,它接受一个a、一个函数a -&gt; Bool 并返回一个Maybe a。停止! Hoogle time。没有完全匹配,但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
  • @is7s:我不确定你的意思。类型为MonadPlus m =&gt; (a -&gt; Bool) -&gt; a -&gt; m a。如果为真,则结果为return x,否则为mzero
  • +1 停止!胡歌时间。 :) 请注意 Landei 的回答,只是简单的旧 mfilter,是第四次点击。
【解决方案3】:

您可以使用guard 来实现此行为:

guard (pred x) >> return x

这是一种非常有用的行为,我什至在我自己的一次性代码中定义了ensure(每个人都有这样的东西,对吧?;-):

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

【讨论】:

  • 稍微笼统一些:ensure p x = x &lt;$ guard (p x) 其中&lt;$ 来自Control.Applicative。一点点免费:ensure p = ap (&lt;$) (guard . p) :)
  • @benmachine 这真的更笼统吗? guard 已经需要MonadPlus,所以你仍然不能在非单子应用程序上使用你的ensure
  • 哦,好点。如果我真的想要,我可以改为使用 Alternative,但这可能不值得:) &lt;$ 仍然更可爱。
【解决方案4】:

用途:

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

来自 Data.Bool.HT。

【讨论】:

  • oooo... 这很整洁。从来没有看过那个模块。谢谢!
  • 我相信它应该用于中缀:(5 &gt; 2) ?: (Just 5, Nothing)
  • 除了节省几个字符之外,我真的看不出它在if/then/else 之外提供了什么;您仍然在不必要地重复 5 术语,并且不得不提及 Nothingmfilter 解决方案更胜一筹。
  • 使用utility-ht 包你可以使用toMaybe 而不是(?:) => toMaybe (pred x) x
【解决方案5】:
f 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

如果你看不出来,这不是一个非常严肃的答案。其他人更有洞察力,但我无法抗拒“让这段代码更短”的诙谐回应。

【讨论】:

    【解决方案6】:

    通常我是非常通用代码的忠实拥护者,但实际上我发现这个确切的函数经常有用,专门用于 Maybe,我保留它而不是使用 guardmfilter 和喜欢。

    我给它起的名字是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 用于指示谓词的结果。

    对于像这样的专业版本,你真的没有什么可以让它更短。这已经很简单了。在简洁和仅仅为了字符数而打高尔夫球之间有一条很好的界限,对于这么简单的事情,我真的不会担心尝试“改进”它......

    【讨论】:

    • @hammar:哈哈哈。使用λ&gt; 的流行趋势激发了我改变我的想法,而且……我想这在当时似乎是个好主意?
    猜你喜欢
    • 1970-01-01
    • 2013-01-14
    • 2017-08-19
    • 1970-01-01
    • 1970-01-01
    • 2014-12-10
    • 2020-01-29
    • 2010-12-08
    • 1970-01-01
    相关资源
    最近更新 更多