比计算单位列表的长度更好的方法

时间:2012-01-18 02:52:33

标签: list haskell idiomatic

我有时会发现自己编写这样的代码:

someFunc :: Foo -> Int
someFunc foo = length $ do
  x <- someList
  guard someGuard
  return ()

或等效地:

someFunc foo = length [() | x <- someList, someGuard]

有没有更好的方法来执行这种计算?更高效?更具可读性?更惯用吗?

2 个答案:

答案 0 :(得分:8)

的Primo

guard someGuard
return ()

是多余的,如果条件为真,guard已经返回()。然后我认为someGuard实际上取决于x,否则它将是if someGuard then length someList else 0。通常的写作方式是

someFunc foo = filter (\x -> someGuard) someList

如果情况真的像你的例子看起来那么简单。对于更复杂的情况,使用您的示例样式之一是最直接的方式。如果事情变得非常复杂,我会发现这种做法更为可取。

答案 1 :(得分:6)

如果您发现自己反复编程到模式,那么要做的是编写一个更高阶的函数来封装该模式。您可以使用您拥有的主体,但为了完全确信您的代码没有分配,我建议使用foldl并严格应用增量运算符:

numberSatisfying :: Integral n => (a -> Bool) -> [a] -> n
numberSatisfying p = foldl (\n x -> if p x then (+1) $! n else n) 0

我使用QuickCheck确认此代码与原始代码相同。 (是的,QuickCheck将使用随机谓词进行测试非常酷。)