速いnubが欲しい.(Haskell)

The Haskell 98 Library Report: List Utilities
によると,

nub              :: (Eq a) => [a] -> [a]
nub []           =  []
nub (x:xs)       =  x : nub (filter (\y -> not (x == y)) xs)

なので,実はnubはO(n^2). Eq だけ,だから仕方ないのかもしれないが.


しかし,

nub :: (Ord a) => [a] -> [a]

にすれば,O(n log n) にできる.Setのmember, insertは log n であることを利用する.

import Data.Set (empty, member, insert)

nub' :: (Ord a) => [a] -> [a]
nub' l = nub'' l empty
    where nub'' [] _         = []
          nub'' (x:xs) s
              | x `member` s = nub'' xs s
              | otherwise    = x : nub'' xs (x `insert` s)


O(n^2) と O(n log n) では大違いです. cf. sort



ところで,ソース
http://haskell.org/ghc/docs/latest/html/libraries/base/src/Data-List.html#nub
を見てみたら,#ifdef USE_REPORT_PRELUDE なんて文がある.どうやらnubの実装には2種類あるみたい.
しかし,自分のghcはどちらを使っているのか?

nub                     :: (Eq a) => [a] -> [a]
#ifdef USE_REPORT_PRELUDE
nub                     =  nubBy (==)
#else
-- stolen from HBC
nub l                   = nub' l []             -- '
  where
    nub' [] _           = []                    -- '
    nub' (x:xs) ls                              -- '
        | x `elem` ls   = nub' xs ls            -- '
        | otherwise     = x : nub' xs (x:ls)    -- '
#endif

-- | The 'nubBy' function behaves just like 'nub', except it uses a
-- user-supplied equality predicate instead of the overloaded '=='
-- function.
nubBy                   :: (a -> a -> Bool) -> [a] -> [a]
#ifdef USE_REPORT_PRELUDE
nubBy eq []             =  []
nubBy eq (x:xs)         =  x : nubBy eq (filter (\ y -> not (eq x y)) xs)
#else
nubBy eq l              = nubBy' l []
  where
    nubBy' [] _         = []
    nubBy' (y:ys) xs
       | elem_by eq y xs = nubBy' ys xs
       | otherwise       = y : nubBy' ys (y:xs)

-- Not exported:
-- Note that we keep the call to `eq` with arguments in the
-- same order as in the reference implementation
-- 'xs' is the list of things we've seen so far, 
-- 'y' is the potential new element
elem_by :: (a -> a -> Bool) -> a -> [a] -> Bool
elem_by _  _ []         =  False
elem_by eq y (x:xs)     =  y `eq` x || elem_by eq y xs
#endif


# log は定数だから, O(n log n) => O(n).やったリニアだ.