2012-01-18 52 views
6

我有时会发现自己写的代码这样的长度一种更好的方式:比计数单位名单

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

或等价:

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

是否有进行这种更好的办法的计算?更高效?更可读?更习惯?

回答

6

如果你发现自己反复编程到一个模式,要做的事情是编写一个高阶函数来封装该模式。你可以使用你的身体,但为了要完全相信,你的代码不分配,我会建议使用foldl和增量运营商的严格应用:

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

我已经使用快速检查,以确认此相当于您的原始代码的代码。 (是的,QuickCheck会用随机谓词测试非常酷。)

+3

为什么不'foldl''? – 2012-01-18 06:09:02

+0

@trinithis不在Prelude中... – 2012-01-21 18:59:54

8

普里莫

guard someGuard 
return() 

是多余的,guard已经返回()如果条件为真。那么我想someGuard实际上取决于x,否则它会是if someGuard then length someList else 0。通常的写法是

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

如果情况真的很像你的例子看起来那么简单。对于更复杂的情况,使用您的示例样式之一是最直接的方法。如果情况变得非常复杂,我觉得这个符号更合适。

+0

+1是的,'someList'依赖于'foo','someGuard'依赖于'foo'和'x'。过滤器表达式可能是最简单的捕获方法。 – 2012-01-18 04:22:56