2012-01-18 51 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