我寫了通用量化函數exists
,forall
和none
爲Haskell的內置[]
列表數據類型。在多次情況下,這些證明比Prelude
/Data.List
的any
和all
更有效。我天真地懷疑這個表現是由於any
和all
使用Θ(n)摺疊實現的。由於我對Haskell相對比較陌生,並且一般都會抽象自動符號操縱符,所以我認爲我必須弄錯了,否則這種現象會有一個很好的理由。Haskell/GHC性能的`任何'/`所有`
從Data.Foldable
:
-- | Determines whether any element of the structure satisfies the predicate.
any :: Foldable t => (a -> Bool) -> t a -> Bool
any p = getAny #. foldMap (Any #. p)
-- | Determines whether all elements of the structure satisfy the predicate.
all :: Foldable t => (a -> Bool) -> t a -> Bool
all p = getAll #. foldMap (All #. p)
我實現:
exists :: (a -> Bool) -> [a] -> Bool
exists _ [] = False
exists pred (x : xs) | pred x = True
| otherwise = exists pred xs
resultive
forall pred = not . exists (not . pred)
none pred = not . exists pred = forall (not . pred)
消除布爾倒置:
forall, none :: (a -> Bool) -> [a] -> Bool
forall _ [] = True
forall pred (x : xs) | pred x = forall pred xs
| otherwise = False
none _ [] = True
none pred (x : xs) | pred x = False
| otherwise = none pred xs
all
:
time 327.8 μs (322.4 μs .. 333.0 μs)
0.997 R² (0.996 R² .. 0.998 R²)
mean 328.7 μs (324.1 μs .. 334.2 μs)
std dev 16.95 μs (14.63 μs .. 22.02 μs)
和forall
:使用標準的nf
測量
time 113.2 μs (111.2 μs .. 115.0 μs)
0.997 R² (0.996 R² .. 0.998 R²)
mean 112.0 μs (110.0 μs .. 113.9 μs)
std dev 6.333 μs (5.127 μs .. 7.896 μs)
性能。
正如預期的那樣,我沒有重新推翻摺疊,但低估了編譯器標誌。
我天真地沒有想到-O2
與默認的優化級別性能相比產生如此巨大的整體差異,也沒有在個人自定義編寫和庫文件制定之間的優化效果不一致。許多高效的專業標準功能優化顯然只有在明確啓用時纔會啓動。
Haskell標記信息的「性能」部分強調測試代碼效率時優化級別編譯器標誌的重要性。一般建議相信庫函數實現的複雜性,而不是重新編譯或重新編寫基本表單,以嘗試利用已經培育出來的優化潛力。
如果你想推測這個級別的代碼的性能,你可能應該看看核心。性能差距與漸近無關(它怎麼可能呢?你的函數顯然是O(n)) - 我的猜測是這是因爲'Foldable'函數缺乏內聯。對於某些'f','z'和'List.foldr',你所有的函數都等價於'foldr f z',即使'Foldable.foldr'沒有。 – user2407038
你能分享你的基準嗎? –
我無法用簡單的'all' /'forall'重現這一點。不出所料,在涉及融合操作的情況下,它不是競賽:http://sprunge.us/RQdO當然,您可以爲'forall'和公司編寫融合規則。 – Michael