有条件地建立一个列表
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) => t a -> (a -> f x) -> f ()
,但在这种情况下,t a
必须是 Bool
,这是不可能的。【参考方案2】:
在这种情况下,我喜欢将concat
与列表推导一起使用:
concat
[ [a | opt1]
, [b | opt2]
, [c | opt3]
]
如果opt1
为False,则[a | opt1]
为空列表,否则为仅包含a
的单例列表。
您也可以使用<$
和guard
:
concat
[ a <$ guard opt1
, b <$ guard opt2
, c <$ guard opt3
]
我认为在 base 的任何地方都不存在 onlyIf
函数。
【讨论】:
当a
已经是一个列表时,保护技巧也可以与<*
一起使用。猜猜,那我就不需要特殊功能了。以上是关于有条件地建立一个列表的主要内容,如果未能解决你的问题,请参考以下文章