有条件地建立一个列表

Posted

技术标签:

【中文标题】有条件地建立一个列表【英文标题】:Conditionally building a list 【发布时间】:2014-09-23 07:45:41 【问题描述】:

我想从 Haskell 中的一堆其他预定义变量构建一个命令行参数列表。与许多命令行参数的性质一样,这些参数要么存在,要么不存在。

在 Haskell 中有条件地构建列表有一个通用的习惯用法吗? if-then-else 方法感觉相当乏味:

import Control.Monad
join [ if opt1 then [a] else []
     , if opt2 then [b] else []
     , if opt3 then [c] else [] ]

-- gives me back [a, c] or something like that.

我有类似的东西

onlyIf :: MonadPlus m => a -> Bool -> m a
onlyIf a p = if p then return a else mzero

mwhen :: Monoid a => Bool -> a -> a
mwhen p a = if p then a else mempty

记住,然后可以像这样使用

a `onlyIf` opt1 <>
b `onlyIf` opt2 <>
c `onlyIf` opt3

mwhen opt1 [a] <>
mwhen opt2 [b] <>
mwhen opt3 [c]

Hoogle 在这里并没有真正的帮助,当然,可能有更好(/更常见)的方式来做这些事情。

【问题讨论】:

concatMap snd . filter fst 怎么样 :) @josejuan 没想到。似乎绝对比我自己的例子更惯用。 :) 【参考方案1】:

您可以使用Writer(请参阅此question)并使用when 而不是Maybe。 但是使用Maybe而不是条件,结果会更好。

【讨论】:

这甚至没有类型检查。 forM_ :: (Applicative f, Foldable t) =&gt; t a -&gt; (a -&gt; f x) -&gt; f (),但在这种情况下,t a 必须是 Bool,这是不可能的。【参考方案2】:

在这种情况下,我喜欢将concat 与列表推导一起使用:

concat
  [ [a | opt1]
  , [b | opt2]
  , [c | opt3]
  ]

如果opt1 为False,则[a | opt1] 为空列表,否则为仅包含a 的单例列表。

您也可以使用&lt;$guard

concat
  [ a <$ guard opt1
  , b <$ guard opt2
  , c <$ guard opt3
  ]

我认为在 base 的任何地方都不存在 onlyIf 函数。

【讨论】:

a 已经是一个列表时,保护技巧也可以与&lt;* 一起使用。猜猜,那我就不需要特殊功能了。

以上是关于有条件地建立一个列表的主要内容,如果未能解决你的问题,请参考以下文章

如何根据列表有条件地更新 Pandas 中的 DataFrame 列

将组件保存到列表中,然后有条件地渲染

如何有条件地将元素插入列表?

有条件地从 Java 8 中的列表中删除元素 [重复]

如何有条件地将小部件添加到列表中?

使用 CMake 生成器表达式有条件地链接到库列表