首先,讓我重寫你的函數一點,因爲
isListOk :: Bool
isListOk = length (filter isItemOk [1 .. 1000]) <= 3
可以說是比你的版本更地道。 (請注意,我也改變了類型簽名和你是不正確的。此外,你應該寫1 .. 1000
而非1.1000
)
懶惰的評價是在這裏你最好的朋友,因爲它通常會確保沒有不必要的計算將是執行。
不幸的是,您在使用length
(或將列表中的每個元素映射到1,然後總結結果列表,就像你這樣做)正在阻礙你。也就是說,length
在列表的脊柱中是嚴格的:只有當列表的長度達到最後才能產生列表的長度,在這種情況下,這意味着您的程序必須運行您的支票一千次。
一種解決方案是將長度的計算(即,中,列表的脊柱的遍歷)和測試是否所計算的長度不超過一個給定閾值到一個單一的功能即實際上在它的參數列表的脊柱懶:
isNotLongerThan :: [a] -> Integer -> Bool
isNotLongerThan [] n = n >= 0
isNotLongerThan (_ : xs) n = n >= 1 && isNotLongerThan xs (n - 1)
然後寫
isListOk :: Bool
isListOk = filter isItemOk [1 .. 1000] `isNotLongerThan` 3
對於可重複使用的解決方案,可以在謂語和閾值兩者當然摘要:
forNoMoreThan :: (a -> Bool) -> Integer -> [a] -> Bool
forNoMoreThan p n = (`isNotLongerThan` n) . filter p
isListOk :: Bool
isListOk = (isItemOk `forNoMoreThan` 3) [1 .. 1000]
最後,哈馬爾指出,如果你的脫粒舊的足夠小並且固定,您可以簡單地使用模式匹配來確定列表是否足夠短。
由於'take'和'list comprehension'是懶惰的,你的函數不會超越4。如果你知道你的號碼不會超出限制,那麼嘗試使用'Int',因爲它比'Integer'快得多。它是'Bool'而不是'Boolean'。 'isListOk'應該帶一個列表參數。 – Satvik