我有时会发现自己编写这样的代码:
someFunc :: Foo -> Int
someFunc foo = length $ do
x <- someList
guard someGuard
return ()
或等效地:
someFunc foo = length [() | x <- someList, someGuard]
有没有更好的方法来执行这种计算?更高效?更具可读性?更惯用吗?
答案 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将使用随机谓词进行测试非常酷。)