2016-10-11 10 views
3

予想通りf1,f2O(i・log i)です。ここで何が起こっているのですか?ハスケル:Data.Set `notMember`は` notElem`より遅いですか?

import Data.Set 

i = 20000 

-- should be slow 
f1 = [ x | x <- [1..i] , x `notElem` [2..i-1] ] 
-- should be fast 
f2 = [ x | x <- [1..i] , x `notMember` fromAscList [2..i-1] ] 

GHCiの出力は:

*Main> f1 
[1,20000] 
(7.12 secs, 16,013,697,360 bytes) 
*Main> f2 
[1,20000] 
(44.27 secs, 86,391,426,456 bytes) 

答えて

6

これは、最適化はまだ起こっていないという理由だけです。あなたはファイルF.hsに次のように置く場合:

module F (f1,f2) where 

import Data.Set 

-- should be slow 
f1 :: Int -> [Int] 
f1 i = [ x | x <- [1..i] , x `notElem` [2..i-1] ] 
-- should be fast 
f2 :: Int -> [Int] 
f2 i = [ x | x <- [1..i] , x `notMember` fromAscList [2..i-1] ] 

と最適化で最初にそれをコンパイルするには、次を得る:

$ ghc -O2 F.hs  # compile with optimizations 
[1 of 1[ Compiling F   (F.hs, F.o) 

$ ghci F.hs   # now load it up in GHCi 
GHCi, version 8.0.1: http://www.haskell.org/ghc/ :? for help 
Ok, modules loaded: F (F.o) 
Prelude F> :set +s 
Prelude F> f1 20000 
[1,20000] 
(2.16 secs, 2,030,440 bytes) 
Prelude F> f2 20000 
[1,20000] 
(0.05 secs, 4,591,312 bytes) 

私の推測では、あなたの状況にあなたがfromAscList [2..i-1]複数回の再計算GHCiのを持っていたということです、または類似のもの。

+4

変更が重要であることを確認するのは楽しいので、手動でさまざまな最適化を適用することもできます。私の実験から、重要な2人はセットの定義を解除し、それが単相性であることを確認しています。 ghciで '' 'let s = fromAscList [2..i-1] :: [x | x [ - [1..i]、x 'notMember's]' ''はインスタントで、 '' 'はlet s = [2..i-1] :: [Integer] in [x | x < - [1..i]、x 'notElem's'''はOPのリストベースコードの約2倍の速さですが、' Set'バージョンよりもまだ遅いです。 –

+0

私はそれを解釈するのではなく、コンパイルされたバージョンをロードするために 'ghci -fobject-code'とすべきだと思います。 (もちろんモジュールに 'main'があるので答えには影響しません) – user2407038

+0

@ user2407038オブジェクトファイルがすでにそこにあれば、コンパイルされたバージョンがロードされていると思います。 )。 – Alec

関連する問題