diff --git a/Data/EnumMap.hs b/Data/EnumMap.hs
--- a/Data/EnumMap.hs
+++ b/Data/EnumMap.hs
@@ -1,533 +1,41 @@
-{-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-
 -- |
 -- Module      :  $Header$
 -- Description :  Data.IntMap with Enum keys.
--- Copyright   :  (c) 2011 Michal Terepeta
+-- Copyright   :  (c) 2011-2013 Michal Terepeta
 -- License     :  BSD3
 -- Maintainer  :  michal.terepeta@gmail.com
 -- Stability   :  alpha
--- Portability :  uses GeneralizedNewtypeDeriving
+-- Portability :  uses DeriveDataTypeable and GeneralizedNewtypeDeriving
 
 -- This is a simple wrapper for 'Data.IntMap' that works with any type of keys
--- that are instances of 'Enum' type class. Useful if one wants to have the
--- performance of 'Data.IntMap' and at the same time use something else than
--- 'Int's (e.g. an 'Int' wrapped with newtype). For documentation please see the
+-- that are instances of 'Enum' type class.  For documentation please see the
 -- one for 'Data.IntMap'.
 
 module Data.EnumMap
-  ( EnumMap
-
-  -- * Wrapping/unwrapping
-  , intMapToEnumMap
-  , enumMapToIntMap
-
-  -- * Operators
-  , (!)
-  , (\\)
-
-  -- * Query
-  , null
-  , size
-  , member
-  , notMember
-  , lookup
-  , findWithDefault
-
-  -- * Construction
-  , empty
-  , singleton
-
-  -- ** Insertion
-  , insert
-  , insertWith
-  , insertWithKey
-  , insertLookupWithKey
-
-  -- ** Delete\/Update
-  , delete
-  , adjust
-  , adjustWithKey
-  , update
-  , updateWithKey
-  , updateLookupWithKey
-  , alter
-
-  -- * Combine
-
-  -- ** Union
-  , union
-  , unionWith
-  , unionWithKey
-  , unions
-  , unionsWith
-
-  -- ** Difference
-  , difference
-  , differenceWith
-  , differenceWithKey
-
-  -- ** Intersection
-  , intersection
-  , intersectionWith
-  , intersectionWithKey
-
-  -- ** Universal combining function
-  , mergeWithKey
-
-  -- * Traversal
-  -- ** Map
-  , map
-  , mapWithKey
-  , mapAccum
-  , mapAccumWithKey
-  , mapAccumRWithKey
-
-  -- ** Fold
+  ( module Data.EnumMap.Lazy
+  , insertWith'
+  , insertWithKey'
   , fold
   , foldWithKey
-
-  -- * Conversion
-  , elems
-  , keys
-  , keysSet
-  , assocs
-
-  -- ** Lists
-  , toList
-  , fromList
-  , fromListWith
-  , fromListWithKey
-
-  -- ** Ordered lists
-  , toAscList
-  , fromAscList
-  , fromAscListWith
-  , fromAscListWithKey
-  , fromDistinctAscList
-
-  -- * Filter
-  , filter
-  , filterWithKey
-  , partition
-  , partitionWithKey
-
-  , mapMaybe
-  , mapMaybeWithKey
-  , mapEither
-  , mapEitherWithKey
-
-  , split
-  , splitLookup
-
-  -- * Submap
-  , isSubmapOf
-  , isSubmapOfBy
-  , isProperSubmapOf
-  , isProperSubmapOfBy
-
-  -- * Min\/Max
-  , findMin
-  , findMax
-  , deleteMin
-  , deleteMax
-  , deleteFindMin
-  , deleteFindMax
-  , updateMin
-  , updateMax
-  , updateMinWithKey
-  , updateMaxWithKey
-  , minView
-  , maxView
-  , minViewWithKey
-  , maxViewWithKey
   ) where
 
-import Prelude hiding ( filter, lookup, map, null )
-import qualified Prelude as P
-
-import Data.IntMap ( IntMap )
-import qualified Data.IntMap as I
-
-import Data.EnumSet ( EnumSet )
-import qualified Data.EnumSet as EnumSet
-
-import Control.Arrow ( first, second, (***) )
-import Data.Foldable ( Foldable )
-import Data.Monoid ( Monoid )
-import Data.Traversable ( Traversable )
-import Data.Typeable ( Typeable )
-
-import Text.Read
-
--- | Wrapper for 'IntMap' with 'Enum' keys.
-newtype EnumMap k a = EnumMap { unWrap :: IntMap a }
-  deriving (Eq, Foldable, Functor, Ord, Monoid, Traversable, Typeable)
-
-instance (Enum k, Show k, Show a) => Show (EnumMap k a) where
-  showsPrec p em = showParen (p > 10) $
-    showString "fromList " . shows (toList em)
-
-instance (Enum k, Read k, Read a) => Read (EnumMap k a) where
-  readPrec = parens . prec 10 $ do
-    Ident "fromList" <- lexP
-    list <- readPrec
-    return (fromList list)
-
---
--- Conversion to/from 'IntMap'.
---
-
--- | Wrap 'IntMap'.
-intMapToEnumMap :: IntMap a -> EnumMap k a
-intMapToEnumMap = EnumMap
-
--- | Unwrap 'IntMap'.
-enumMapToIntMap :: EnumMap k a -> IntMap a
-enumMapToIntMap = unWrap
-
---
--- A few useful functions used through the module. Not exported.
---
-
-pairWrap :: (IntMap a, IntMap b) -> (EnumMap k a, EnumMap k b)
-pairWrap = EnumMap *** EnumMap
-{-# INLINE pairWrap #-}
-
---
--- Here begins the main part.
---
-
-(!) :: (Enum k) => EnumMap k a -> k -> a
-(EnumMap im) ! k = im I.! (fromEnum k)
-{-# INLINE (!) #-}
-
-(\\) :: EnumMap k a -> EnumMap k b -> EnumMap k a
-(EnumMap im1) \\ (EnumMap im2) = EnumMap $ im1 I.\\ im2
-{-# INLINE (\\) #-}
-
-null :: EnumMap k a -> Bool
-null = I.null . unWrap
-{-# INLINE null #-}
-
-size :: EnumMap k a -> Int
-size = I.size . unWrap
-{-# INLINE size #-}
-
-member :: (Enum k) => k -> EnumMap k a -> Bool
-member k = I.member (fromEnum k) . unWrap
-{-# INLINE member #-}
-
-notMember :: (Enum k) => k -> EnumMap k a -> Bool
-notMember k = I.notMember (fromEnum k) . unWrap
-{-# INLINE notMember #-}
-
-lookup :: (Enum k) => k -> EnumMap k a -> Maybe a
-lookup k = I.lookup (fromEnum k) . unWrap
-{-# INLINE lookup #-}
-
-findWithDefault :: (Enum k) => a -> k -> EnumMap k a -> a
-findWithDefault def k = I.findWithDefault def (fromEnum k) . unWrap
-{-# INLINE findWithDefault #-}
-
-empty :: EnumMap k a
-empty = EnumMap $ I.empty
-{-# INLINE empty #-}
-
-singleton :: (Enum k) => k -> a -> EnumMap k a
-singleton k = EnumMap . I.singleton (fromEnum k)
-{-# INLINE singleton #-}
-
-insert :: (Enum k) => k -> a -> EnumMap k a -> EnumMap k a
-insert k a = EnumMap . I.insert (fromEnum k) a . unWrap
-{-# INLINE insert #-}
-
-insertWith :: (Enum k) => (a -> a -> a) -> k -> a -> EnumMap k a -> EnumMap k a
-insertWith f k a = EnumMap . I.insertWith f (fromEnum k) a . unWrap
-{-# INLINE insertWith #-}
-
-insertWithKey :: (Enum k) => (k -> a -> a -> a) -> k -> a -> EnumMap k a -> EnumMap k a
-insertWithKey f k a = EnumMap . I.insertWithKey (f . toEnum) (fromEnum k) a . unWrap
-{-# INLINE insertWithKey #-}
-
-insertLookupWithKey :: (Enum k) => (k -> a -> a -> a) -> k -> a -> EnumMap k a -> (Maybe a, EnumMap k a)
-insertLookupWithKey f k a = second EnumMap . I.insertLookupWithKey (f . toEnum) (fromEnum k) a . unWrap
-{-# INLINE insertLookupWithKey #-}
-
-delete :: (Enum k) => k -> EnumMap k a -> EnumMap k a
-delete k = EnumMap . I.delete (fromEnum k) . unWrap
-{-# INLINE delete #-}
-
-adjust ::  (Enum k) => (a -> a) -> k -> EnumMap k a -> EnumMap k a
-adjust f k = EnumMap . I.adjust f (fromEnum k) . unWrap
-{-# INLINE adjust #-}
-
-adjustWithKey :: (Enum k) => (k -> a -> a) -> k -> EnumMap k a -> EnumMap k a
-adjustWithKey f k = EnumMap . I.adjustWithKey (f . toEnum) (fromEnum k) . unWrap
-{-# INLINE adjustWithKey #-}
-
-update ::  (Enum k) => (a -> Maybe a) -> k -> EnumMap k a -> EnumMap k a
-update f k = EnumMap . I.update f (fromEnum k) . unWrap
-{-# INLINE update #-}
-
-updateWithKey ::  (Enum k) => (k -> a -> Maybe a) -> k -> EnumMap k a -> EnumMap k a
-updateWithKey f k = EnumMap . I.updateWithKey (f . toEnum) (fromEnum k) . unWrap
-{-# INLINE updateWithKey #-}
-
-updateLookupWithKey ::  (Enum k) => (k -> a -> Maybe a) -> k -> EnumMap k a -> (Maybe a,EnumMap k a)
-updateLookupWithKey f k = second EnumMap . I.updateLookupWithKey (f . toEnum) (fromEnum k) . unWrap
-{-# INLINE updateLookupWithKey #-}
-
-alter :: (Enum k) => (Maybe a -> Maybe a) -> k -> EnumMap k a -> EnumMap k a
-alter f k = EnumMap . I.alter f (fromEnum k) . unWrap
-{-# INLINE alter #-}
-
-unions :: [EnumMap k a] -> EnumMap k a
-unions = EnumMap . I.unions . P.map unWrap
-{-# INLINE unions #-}
-
-unionsWith :: (a -> a -> a) -> [EnumMap k a] -> EnumMap k a
-unionsWith f = EnumMap . I.unionsWith f . P.map unWrap
-{-# INLINE unionsWith #-}
-
-union :: EnumMap k a -> EnumMap k a -> EnumMap k a
-union (EnumMap im1) (EnumMap im2) = EnumMap $ I.union im1 im2
-{-# INLINE union #-}
-
-unionWith :: (a -> a -> a) -> EnumMap k a -> EnumMap k a -> EnumMap k a
-unionWith f (EnumMap im1) (EnumMap im2) = EnumMap $ I.unionWith f im1 im2
-{-# INLINE unionWith #-}
-
-unionWithKey :: (Enum k) => (k -> a -> a -> a) -> EnumMap k a -> EnumMap k a -> EnumMap k a
-unionWithKey f (EnumMap im1) (EnumMap im2) = EnumMap $ I.unionWithKey (f . toEnum) im1 im2
-{-# INLINE unionWithKey #-}
-
-difference :: EnumMap k a -> EnumMap k b -> EnumMap k a
-difference (EnumMap im1) (EnumMap im2) = EnumMap $ I.difference im1 im2
-{-# INLINE difference #-}
-
-differenceWith :: (a -> b -> Maybe a) -> EnumMap k a -> EnumMap k b -> EnumMap k a
-differenceWith f (EnumMap im1) (EnumMap im2) = EnumMap $ I.differenceWith f im1 im2
-{-# INLINE differenceWith #-}
-
-differenceWithKey :: (Enum k) => (k -> a -> b -> Maybe a) -> EnumMap k a -> EnumMap k b -> EnumMap k a
-differenceWithKey f (EnumMap im1) (EnumMap im2) = EnumMap $ I.differenceWithKey (f . toEnum) im1 im2
-{-# INLINE differenceWithKey #-}
-
-intersection :: EnumMap k a -> EnumMap k b -> EnumMap k a
-intersection (EnumMap im1) (EnumMap im2) = EnumMap $ I.intersection im1 im2
-{-# INLINE intersection #-}
-
-intersectionWith :: (a -> b -> c) -> EnumMap k a -> EnumMap k b -> EnumMap k c
-intersectionWith f (EnumMap im1) (EnumMap im2) = EnumMap $ I.intersectionWith f im1 im2
-{-# INLINE intersectionWith #-}
-
-intersectionWithKey :: (Enum k) => (k -> a -> b -> c) -> EnumMap k a -> EnumMap k b -> EnumMap k c
-intersectionWithKey f (EnumMap im1) (EnumMap im2) = EnumMap $ I.intersectionWithKey (f . toEnum) im1 im2
-{-# INLINE intersectionWithKey #-}
-
-mergeWithKey :: (Enum k) => (k -> a -> b -> Maybe c) ->
-    (EnumMap k a -> EnumMap k c) -> (EnumMap k b -> EnumMap k c) ->
-    EnumMap k a -> EnumMap k b -> EnumMap k c
-mergeWithKey f ga gb = \ ma mb -> EnumMap $
-    I.mergeWithKey (f . toEnum) (unWrap . ga . EnumMap) (unWrap . gb . EnumMap) (unWrap ma) (unWrap mb)
-{-# INLINE mergeWithKey #-}
-
-updateMinWithKey :: (Enum k) => (k -> a -> Maybe a) -> EnumMap k a -> EnumMap k a
-updateMinWithKey f = EnumMap . I.updateMinWithKey (f . toEnum) . unWrap
-{-# INLINE updateMinWithKey #-}
-
-updateMaxWithKey :: (Enum k) => (k -> a -> Maybe a) -> EnumMap k a -> EnumMap k a
-updateMaxWithKey f = EnumMap . I.updateMaxWithKey (f . toEnum) . unWrap
-{-# INLINE updateMaxWithKey #-}
-
-maxViewWithKey :: (Enum k) => EnumMap k a -> Maybe ((k, a), EnumMap k a)
-maxViewWithKey = fmap wrap . I.maxViewWithKey . unWrap
-  where
-    wrap ((i, a), im) = ((toEnum i, a), EnumMap im)
-{-# INLINE maxViewWithKey #-}
-
-minViewWithKey :: (Enum k) => EnumMap k a -> Maybe ((k, a), EnumMap k a)
-minViewWithKey =  fmap wrap . I.minViewWithKey . unWrap
-  where
-    wrap ((i, a), imap) = ((toEnum i, a), EnumMap imap)
-{-# INLINE minViewWithKey #-}
-
-updateMax :: (a -> Maybe a) -> EnumMap k a -> EnumMap k a
-updateMax f = EnumMap . I.updateMax f . unWrap
-{-# INLINE updateMax #-}
-
-updateMin :: (a -> Maybe a) -> EnumMap k a -> EnumMap k a
-updateMin f = EnumMap . I.updateMin f . unWrap
-{-# INLINE updateMin #-}
-
-maxView :: EnumMap k a -> Maybe (a, EnumMap k a)
-maxView = fmap (second EnumMap) . I.maxView . unWrap
-{-# INLINE maxView #-}
-
-minView :: EnumMap k a -> Maybe (a, EnumMap k a)
-minView = fmap (second EnumMap) . I.minView . unWrap
-{-# INLINE minView #-}
-
-deleteFindMax :: (Enum k) => EnumMap k a -> ((k, a), EnumMap k a)
-deleteFindMax = (first toEnum *** EnumMap) . I.deleteFindMax . unWrap
-{-# INLINE deleteFindMax #-}
-
-deleteFindMin :: (Enum k) => EnumMap k a -> ((k, a), EnumMap k a)
-deleteFindMin = (first toEnum *** EnumMap) . I.deleteFindMin . unWrap
-{-# INLINE deleteFindMin #-}
-
-findMin :: (Enum k) => EnumMap k a -> (k, a)
-findMin = first toEnum . I.findMin . unWrap
-{-# INLINE findMin #-}
-
-findMax :: (Enum k) => EnumMap k a -> (k, a)
-findMax = first toEnum . I.findMax . unWrap
-{-# INLINE findMax #-}
-
-deleteMin :: EnumMap k a -> EnumMap k a
-deleteMin = EnumMap . I.deleteMin . unWrap
-{-# INLINE deleteMin #-}
-
-deleteMax :: EnumMap k a -> EnumMap k a
-deleteMax = EnumMap . I.deleteMax . unWrap
-{-# INLINE deleteMax #-}
-
-isProperSubmapOf :: (Eq a) => EnumMap k a -> EnumMap k a -> Bool
-isProperSubmapOf (EnumMap im1) (EnumMap im2) = I.isProperSubmapOf im1 im2
-{-# INLINE isProperSubmapOf #-}
-
-isProperSubmapOfBy :: (a -> b -> Bool) -> EnumMap k a -> EnumMap k b -> Bool
-isProperSubmapOfBy p (EnumMap im1) (EnumMap im2) = I.isProperSubmapOfBy p im1 im2
-{-# INLINE isProperSubmapOfBy #-}
-
-isSubmapOf :: Eq a => EnumMap k a -> EnumMap k a -> Bool
-isSubmapOf (EnumMap im1) (EnumMap im2) = I.isSubmapOf im1 im2
-{-# INLINE isSubmapOf #-}
-
-isSubmapOfBy :: (a -> b -> Bool) -> EnumMap k a -> EnumMap k b -> Bool
-isSubmapOfBy p (EnumMap im1) (EnumMap im2) = I.isSubmapOfBy p im1 im2
-{-# INLINE isSubmapOfBy #-}
-
-map :: (a -> b) -> EnumMap k a -> EnumMap k b
-map f = EnumMap . I.map f . unWrap
-{-# INLINE map #-}
-
-mapWithKey :: (Enum k) => (k -> a -> b) -> EnumMap k a -> EnumMap k b
-mapWithKey f = EnumMap . I.mapWithKey (f . toEnum) . unWrap
-{-# INLINE mapWithKey #-}
-
-mapAccum :: (a -> b -> (a, c)) -> a -> EnumMap k b -> (a, EnumMap k c)
-mapAccum f a = second EnumMap . I.mapAccum f a . unWrap
-{-# INLINE mapAccum #-}
-
-mapAccumWithKey :: (Enum k) => (a -> k -> b -> (a, c)) -> a -> EnumMap k b -> (a, EnumMap k c)
-mapAccumWithKey f a = second EnumMap . I.mapAccumWithKey (\b -> f b . toEnum) a . unWrap
-{-# INLINE mapAccumWithKey #-}
-
-mapAccumRWithKey :: (Enum k) => (a -> k -> b -> (a, c)) -> a -> EnumMap k b -> (a, EnumMap k c)
-mapAccumRWithKey f a = second EnumMap . I.mapAccumRWithKey (\b -> f b . toEnum) a . unWrap
-{-# INLINE mapAccumRWithKey #-}
-
-filter :: (a -> Bool) -> EnumMap k a -> EnumMap k a
-filter p = EnumMap . I.filter p . unWrap
-{-# INLINE filter #-}
-
-filterWithKey :: (Enum k) => (k -> a -> Bool) -> EnumMap k a -> EnumMap k a
-filterWithKey p = EnumMap . I.filterWithKey (p . toEnum) . unWrap
-{-# INLINE filterWithKey #-}
-
-partition :: (a -> Bool) -> EnumMap k a -> (EnumMap k a, EnumMap k a)
-partition p = pairWrap . I.partition p . unWrap
-{-# INLINE partition #-}
-
-partitionWithKey :: (Enum k) => (k -> a -> Bool) -> EnumMap k a -> (EnumMap k a, EnumMap k a)
-partitionWithKey p = pairWrap . I.partitionWithKey (p . toEnum) . unWrap
-{-# INLINE partitionWithKey #-}
-
-mapMaybe :: (a -> Maybe b) -> EnumMap k a -> EnumMap k b
-mapMaybe f = EnumMap . I.mapMaybe f . unWrap
-{-# INLINE mapMaybe #-}
-
-mapMaybeWithKey :: (Enum k) => (k -> a -> Maybe b) -> EnumMap k a -> EnumMap k b
-mapMaybeWithKey f = EnumMap . I.mapMaybeWithKey (f . toEnum) . unWrap
-{-# INLINE mapMaybeWithKey #-}
+import Prelude hiding ( filter, foldr, foldl, lookup, map, null )
 
-mapEither :: (a -> Either b c) -> EnumMap k a -> (EnumMap k b, EnumMap k c)
-mapEither f = pairWrap . I.mapEither f . unWrap
-{-# INLINE mapEither #-}
+import Data.EnumMap.Lazy
+import Data.EnumMap.Base
 
-mapEitherWithKey :: (Enum k) => (k -> a -> Either b c) -> EnumMap k a -> (EnumMap k b, EnumMap k c)
-mapEitherWithKey f = pairWrap . I.mapEitherWithKey (f . toEnum) . unWrap
-{-# INLINE mapEitherWithKey #-}
+import qualified Data.IntMap as I
 
-split :: (Enum k) => k -> EnumMap k a -> (EnumMap k a, EnumMap k a)
-split k = pairWrap . I.split (fromEnum k) . unWrap
-{-# INLINE split #-}
+insertWith' :: (Enum k) => (a -> a -> a) -> k -> a -> EnumMap k a -> EnumMap k a
+insertWith' f k x = EnumMap . I.insertWith' f (fromEnum k) x . unWrap
 
-splitLookup :: (Enum k) => k -> EnumMap k a -> (EnumMap k a, Maybe a, EnumMap k a)
-splitLookup k = wrap . I.splitLookup (fromEnum k) . unWrap
-  where
-    wrap (im1, ma, im2) = (EnumMap im1, ma, EnumMap im2)
-{-# INLINE splitLookup #-}
+insertWithKey' :: (Enum k)
+  => (k -> a -> a -> a) -> k -> a -> EnumMap k a -> EnumMap k a
+insertWithKey' f k x =
+  EnumMap . I.insertWithKey' (f . toEnum) (fromEnum k) x . unWrap
 
-fold :: (a -> b -> b) -> b -> EnumMap k a -> b
-fold f acc = I.fold f acc . unWrap
-{-# INLINE fold #-}
+fold :: (Enum k) => (a -> b -> b) -> b -> EnumMap k a -> b
+fold f a = I.fold f a . unWrap
 
 foldWithKey :: (Enum k) => (k -> a -> b -> b) -> b -> EnumMap k a -> b
-foldWithKey f acc = I.foldWithKey (f . toEnum) acc . unWrap
-{-# INLINE foldWithKey #-}
-
-elems :: EnumMap k a -> [a]
-elems = I.elems . unWrap
-{-# INLINE elems #-}
-
-keys :: (Enum k) => EnumMap k a -> [k]
-keys = P.map toEnum . I.keys . unWrap
-{-# INLINE keys #-}
-
-keysSet :: (Enum k) => EnumMap k a -> EnumSet k
-keysSet = EnumSet.fromDistinctAscList . keys
-{-# INLINE keysSet #-}
-
-assocs :: (Enum k) => EnumMap k a -> [(k, a)]
-assocs = P.map (first toEnum) . I.assocs . unWrap
-{-# INLINE assocs #-}
-
-toList :: (Enum k) => EnumMap k a -> [(k, a)]
-toList = P.map (first toEnum) . I.toList . unWrap
-{-# INLINE toList #-}
-
-toAscList :: (Enum k) => EnumMap k a -> [(k, a)]
-toAscList = P.map (first toEnum) . I.toAscList . unWrap
-{-# INLINE toAscList #-}
-
-fromList :: (Enum k) => [(k, a)] -> EnumMap k a
-fromList = EnumMap . I.fromList . P.map (first fromEnum)
-{-# INLINE fromList #-}
-
-fromListWith :: (Enum k) => (a -> a -> a) -> [(k, a)] -> EnumMap k a
-fromListWith f = EnumMap . I.fromListWith f . P.map (first fromEnum)
-{-# INLINE fromListWith #-}
-
-fromListWithKey :: (Enum k) => (k -> a -> a -> a) -> [(k, a)] -> EnumMap k a
-fromListWithKey f = EnumMap . I.fromListWithKey (f . toEnum) . P.map (first fromEnum)
-{-# INLINE fromListWithKey #-}
-
-fromAscList :: (Enum k) => [(k, a)] -> EnumMap k a
-fromAscList = EnumMap . I.fromAscList . P.map (first fromEnum)
-{-# INLINE fromAscList #-}
-
-fromAscListWith :: (Enum k) => (a -> a -> a) -> [(k, a)] -> EnumMap k a
-fromAscListWith f = EnumMap . I.fromAscListWith f . P.map (first fromEnum)
-{-# INLINE fromAscListWith #-}
-
-fromAscListWithKey :: (Enum k) => (k -> a -> a -> a) -> [(k, a)] -> EnumMap k a
-fromAscListWithKey f = EnumMap . I.fromAscListWithKey (f . toEnum) . P.map (first fromEnum)
-{-# INLINE fromAscListWithKey #-}
-
-fromDistinctAscList :: (Enum k) => [(k, a)] -> EnumMap k a
-fromDistinctAscList = EnumMap . I.fromDistinctAscList . P.map (first fromEnum)
-{-# INLINE fromDistinctAscList #-}
+foldWithKey f a = I.foldWithKey (f . toEnum) a . unWrap
diff --git a/Data/EnumMap/Base.hs b/Data/EnumMap/Base.hs
new file mode 100644
--- /dev/null
+++ b/Data/EnumMap/Base.hs
@@ -0,0 +1,637 @@
+{-# LANGUAGE DeriveDataTypeable         #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+
+-- |
+-- Module      :  $Header$
+-- Description :  Data.IntMap with Enum keys.
+-- Copyright   :  (c) 2011-2013 Michal Terepeta
+-- License     :  BSD3
+-- Maintainer  :  michal.terepeta@gmail.com
+-- Stability   :  alpha
+-- Portability :  uses DeriveDataTypeable and GeneralizedNewtypeDeriving
+
+module Data.EnumMap.Base
+  ( EnumMap(..)
+
+  -- * Wrapping/unwrapping
+  , intMapToEnumMap
+  , enumMapToIntMap
+
+  -- * Operators
+  , (!)
+  , (\\)
+
+  -- * Query
+  , null
+  , size
+  , member
+  , notMember
+  , lookup
+  , findWithDefault
+  , lookupLT
+  , lookupGT
+  , lookupLE
+  , lookupGE
+
+  -- * Construction
+  , empty
+  , singleton
+
+  -- ** Insertion
+  , insert
+  , insertWith
+  , insertWithKey
+  , insertLookupWithKey
+
+  -- ** Delete\/Update
+  , delete
+  , adjust
+  , adjustWithKey
+  , update
+  , updateWithKey
+  , updateLookupWithKey
+  , alter
+
+  -- * Combine
+
+  -- ** Union
+  , union
+  , unionWith
+  , unionWithKey
+  , unions
+  , unionsWith
+
+  -- ** Difference
+  , difference
+  , differenceWith
+  , differenceWithKey
+
+  -- ** Intersection
+  , intersection
+  , intersectionWith
+  , intersectionWithKey
+
+  -- ** Universal combining function
+  , mergeWithKey
+
+  -- * Traversal
+  -- ** Map
+  , map
+  , mapWithKey
+  , traverseWithKey
+  , mapAccum
+  , mapAccumWithKey
+  , mapAccumRWithKey
+  , mapKeys
+  , mapKeysWith
+  , mapKeysMonotonic
+
+  -- * Folds
+  , foldr
+  , foldl
+  , foldrWithKey
+  , foldlWithKey
+  -- ** Strict folds
+  , foldr'
+  , foldl'
+  , foldrWithKey'
+  , foldlWithKey'
+
+  -- * Conversion
+  , elems
+  , keys
+  , assocs
+  , keysSet
+  , fromSet
+
+  -- ** Lists
+  , toList
+  , fromList
+  , fromListWith
+  , fromListWithKey
+
+  -- ** Ordered lists
+  , toAscList
+  , toDescList
+  , fromAscList
+  , fromAscListWith
+  , fromAscListWithKey
+  , fromDistinctAscList
+
+  -- * Filter
+  , filter
+  , filterWithKey
+  , partition
+  , partitionWithKey
+
+  , mapMaybe
+  , mapMaybeWithKey
+  , mapEither
+  , mapEitherWithKey
+
+  , split
+  , splitLookup
+
+  -- * Submap
+  , isSubmapOf
+  , isSubmapOfBy
+  , isProperSubmapOf
+  , isProperSubmapOfBy
+
+  -- * Min\/Max
+  , findMin
+  , findMax
+  , deleteMin
+  , deleteMax
+  , deleteFindMin
+  , deleteFindMax
+  , updateMin
+  , updateMax
+  , updateMinWithKey
+  , updateMaxWithKey
+  , minView
+  , maxView
+  , minViewWithKey
+  , maxViewWithKey
+  ) where
+
+import Prelude hiding ( filter, foldr, foldl, lookup, map, null )
+import qualified Prelude as P
+
+import Control.Applicative ( Applicative, liftA )
+
+import Data.IntMap.Lazy ( IntMap )
+import qualified Data.IntMap.Lazy as I
+
+import Data.EnumSet ( EnumSet )
+import qualified Data.EnumSet as EnumSet
+
+import Control.Arrow ( first, second, (***) )
+import Control.DeepSeq ( NFData )
+import Data.Foldable ( Foldable )
+import Data.Monoid ( Monoid )
+import Data.Traversable ( Traversable )
+import Data.Typeable ( Typeable )
+
+import Text.Read
+
+-- | Wrapper for 'IntMap' with 'Enum' keys.
+newtype EnumMap k a = EnumMap { unWrap :: IntMap a }
+  deriving (Eq, Foldable, Functor, Ord, Monoid, Traversable, Typeable, NFData)
+
+instance (Enum k, Show k, Show a) => Show (EnumMap k a) where
+  showsPrec p em = showParen (p > 10) $
+    showString "fromList " . shows (toList em)
+
+instance (Enum k, Read k, Read a) => Read (EnumMap k a) where
+  readPrec = parens . prec 10 $ do
+    Ident "fromList" <- lexP
+    list <- readPrec
+    return (fromList list)
+
+--
+-- Conversion to/from 'IntMap'.
+--
+
+-- | Wrap 'IntMap'.
+intMapToEnumMap :: IntMap a -> EnumMap k a
+intMapToEnumMap = EnumMap
+{-# INLINE intMapToEnumMap #-}
+
+-- | Unwrap 'IntMap'.
+enumMapToIntMap :: EnumMap k a -> IntMap a
+enumMapToIntMap = unWrap
+{-# INLINE enumMapToIntMap #-}
+
+--
+-- Here begins the main part.
+--
+
+(!) :: (Enum k) => EnumMap k a -> k -> a
+(EnumMap im) ! k = im I.! (fromEnum k)
+{-# INLINE (!) #-}
+
+(\\) :: EnumMap k a -> EnumMap k b -> EnumMap k a
+(EnumMap im1) \\ (EnumMap im2) = EnumMap $ im1 I.\\ im2
+{-# INLINE (\\) #-}
+
+null :: EnumMap k a -> Bool
+null = I.null . unWrap
+{-# INLINE null #-}
+
+size :: EnumMap k a -> Int
+size = I.size . unWrap
+{-# INLINE size #-}
+
+member :: (Enum k) => k -> EnumMap k a -> Bool
+member k = I.member (fromEnum k) . unWrap
+{-# INLINE member #-}
+
+notMember :: (Enum k) => k -> EnumMap k a -> Bool
+notMember k = I.notMember (fromEnum k) . unWrap
+{-# INLINE notMember #-}
+
+lookup :: (Enum k) => k -> EnumMap k a -> Maybe a
+lookup k = I.lookup (fromEnum k) . unWrap
+{-# INLINE lookup #-}
+
+findWithDefault :: (Enum k) => a -> k -> EnumMap k a -> a
+findWithDefault def k = I.findWithDefault def (fromEnum k) . unWrap
+{-# INLINE findWithDefault #-}
+
+lookupLT :: (Enum k) => k -> EnumMap k a -> Maybe (k, a)
+lookupLT k = fmap (first toEnum) . I.lookupLT (fromEnum k) . unWrap
+{-# INLINE lookupLT #-}
+
+lookupGT :: (Enum k) => k -> EnumMap k a -> Maybe (k, a)
+lookupGT k = fmap (first toEnum) . I.lookupGT (fromEnum k) . unWrap
+{-# INLINE lookupGT #-}
+
+lookupLE :: (Enum k) => k -> EnumMap k a -> Maybe (k, a)
+lookupLE k = fmap (first toEnum) . I.lookupLE (fromEnum k) . unWrap
+{-# INLINE lookupLE #-}
+
+lookupGE :: (Enum k) => k -> EnumMap k a -> Maybe (k, a)
+lookupGE k = fmap (first toEnum) . I.lookupGE (fromEnum k) . unWrap
+{-# INLINE lookupGE #-}
+
+empty :: EnumMap k a
+empty = EnumMap $ I.empty
+{-# INLINE empty #-}
+
+singleton :: (Enum k) => k -> a -> EnumMap k a
+singleton k = EnumMap . I.singleton (fromEnum k)
+{-# INLINE singleton #-}
+
+insert :: (Enum k) => k -> a -> EnumMap k a -> EnumMap k a
+insert k a = EnumMap . I.insert (fromEnum k) a . unWrap
+{-# INLINE insert #-}
+
+insertWith :: (Enum k) => (a -> a -> a) -> k -> a -> EnumMap k a -> EnumMap k a
+insertWith f k a = EnumMap . I.insertWith f (fromEnum k) a . unWrap
+{-# INLINE insertWith #-}
+
+insertWithKey :: (Enum k)
+  => (k -> a -> a -> a) -> k -> a -> EnumMap k a -> EnumMap k a
+insertWithKey f k a = EnumMap . I.insertWithKey (f . toEnum) (fromEnum k) a . unWrap
+{-# INLINE insertWithKey #-}
+
+insertLookupWithKey :: (Enum k)
+  => (k -> a -> a -> a) -> k -> a -> EnumMap k a -> (Maybe a, EnumMap k a)
+insertLookupWithKey f k a =
+  second EnumMap . I.insertLookupWithKey (f . toEnum) (fromEnum k) a . unWrap
+{-# INLINE insertLookupWithKey #-}
+
+delete :: (Enum k) => k -> EnumMap k a -> EnumMap k a
+delete k = EnumMap . I.delete (fromEnum k) . unWrap
+{-# INLINE delete #-}
+
+adjust ::  (Enum k) => (a -> a) -> k -> EnumMap k a -> EnumMap k a
+adjust f k = EnumMap . I.adjust f (fromEnum k) . unWrap
+{-# INLINE adjust #-}
+
+adjustWithKey :: (Enum k) => (k -> a -> a) -> k -> EnumMap k a -> EnumMap k a
+adjustWithKey f k = EnumMap . I.adjustWithKey (f . toEnum) (fromEnum k) . unWrap
+{-# INLINE adjustWithKey #-}
+
+update ::  (Enum k) => (a -> Maybe a) -> k -> EnumMap k a -> EnumMap k a
+update f k = EnumMap . I.update f (fromEnum k) . unWrap
+{-# INLINE update #-}
+
+updateWithKey ::  (Enum k) => (k -> a -> Maybe a) -> k -> EnumMap k a -> EnumMap k a
+updateWithKey f k = EnumMap . I.updateWithKey (f . toEnum) (fromEnum k) . unWrap
+{-# INLINE updateWithKey #-}
+
+updateLookupWithKey ::  (Enum k)
+  => (k -> a -> Maybe a) -> k -> EnumMap k a -> (Maybe a,EnumMap k a)
+updateLookupWithKey f k =
+  second EnumMap . I.updateLookupWithKey (f . toEnum) (fromEnum k) . unWrap
+{-# INLINE updateLookupWithKey #-}
+
+alter :: (Enum k) => (Maybe a -> Maybe a) -> k -> EnumMap k a -> EnumMap k a
+alter f k = EnumMap . I.alter f (fromEnum k) . unWrap
+{-# INLINE alter #-}
+
+unions :: [EnumMap k a] -> EnumMap k a
+unions = EnumMap . I.unions . P.map unWrap
+{-# INLINE unions #-}
+
+unionsWith :: (a -> a -> a) -> [EnumMap k a] -> EnumMap k a
+unionsWith f = EnumMap . I.unionsWith f . P.map unWrap
+{-# INLINE unionsWith #-}
+
+union :: EnumMap k a -> EnumMap k a -> EnumMap k a
+union (EnumMap im1) (EnumMap im2) = EnumMap $ I.union im1 im2
+{-# INLINE union #-}
+
+unionWith :: (a -> a -> a) -> EnumMap k a -> EnumMap k a -> EnumMap k a
+unionWith f (EnumMap im1) (EnumMap im2) = EnumMap $ I.unionWith f im1 im2
+{-# INLINE unionWith #-}
+
+unionWithKey :: (Enum k)
+  => (k -> a -> a -> a) -> EnumMap k a -> EnumMap k a -> EnumMap k a
+unionWithKey f (EnumMap im1) (EnumMap im2) =
+  EnumMap $ I.unionWithKey (f . toEnum) im1 im2
+{-# INLINE unionWithKey #-}
+
+difference :: EnumMap k a -> EnumMap k b -> EnumMap k a
+difference (EnumMap im1) (EnumMap im2) = EnumMap $ I.difference im1 im2
+{-# INLINE difference #-}
+
+differenceWith :: (a -> b -> Maybe a) -> EnumMap k a -> EnumMap k b -> EnumMap k a
+differenceWith f (EnumMap im1) (EnumMap im2) =
+  EnumMap $ I.differenceWith f im1 im2
+{-# INLINE differenceWith #-}
+
+differenceWithKey :: (Enum k)
+  => (k -> a -> b -> Maybe a) -> EnumMap k a -> EnumMap k b -> EnumMap k a
+differenceWithKey f (EnumMap im1) (EnumMap im2) =
+  EnumMap $ I.differenceWithKey (f . toEnum) im1 im2
+{-# INLINE differenceWithKey #-}
+
+intersection :: EnumMap k a -> EnumMap k b -> EnumMap k a
+intersection (EnumMap im1) (EnumMap im2) = EnumMap $ I.intersection im1 im2
+{-# INLINE intersection #-}
+
+intersectionWith :: (a -> b -> c) -> EnumMap k a -> EnumMap k b -> EnumMap k c
+intersectionWith f (EnumMap im1) (EnumMap im2) =
+  EnumMap $ I.intersectionWith f im1 im2
+{-# INLINE intersectionWith #-}
+
+intersectionWithKey :: (Enum k)
+  => (k -> a -> b -> c) -> EnumMap k a -> EnumMap k b -> EnumMap k c
+intersectionWithKey f (EnumMap im1) (EnumMap im2) =
+  EnumMap $ I.intersectionWithKey (f . toEnum) im1 im2
+{-# INLINE intersectionWithKey #-}
+
+mergeWithKey :: (Enum k)
+  => (k -> a -> b -> Maybe c)
+  -> (EnumMap k a -> EnumMap k c)
+  -> (EnumMap k b -> EnumMap k c)
+  -> EnumMap k a
+  -> EnumMap k b
+  -> EnumMap k c
+mergeWithKey f ga gb = \ma mb -> EnumMap $
+  I.mergeWithKey (f . toEnum)
+                 (unWrap . ga . EnumMap)
+                 (unWrap . gb . EnumMap)
+                 (unWrap ma)
+                 (unWrap mb)
+{-# INLINE mergeWithKey #-}
+
+updateMinWithKey :: (Enum k) => (k -> a -> Maybe a) -> EnumMap k a -> EnumMap k a
+updateMinWithKey f = EnumMap . I.updateMinWithKey (f . toEnum) . unWrap
+{-# INLINE updateMinWithKey #-}
+
+updateMaxWithKey :: (Enum k) => (k -> a -> Maybe a) -> EnumMap k a -> EnumMap k a
+updateMaxWithKey f = EnumMap . I.updateMaxWithKey (f . toEnum) . unWrap
+{-# INLINE updateMaxWithKey #-}
+
+maxViewWithKey :: (Enum k) => EnumMap k a -> Maybe ((k, a), EnumMap k a)
+maxViewWithKey = fmap wrap . I.maxViewWithKey . unWrap
+  where
+    wrap ((i, a), im) = ((toEnum i, a), EnumMap im)
+{-# INLINE maxViewWithKey #-}
+
+minViewWithKey :: (Enum k) => EnumMap k a -> Maybe ((k, a), EnumMap k a)
+minViewWithKey =  fmap wrap . I.minViewWithKey . unWrap
+  where
+    wrap ((i, a), imap) = ((toEnum i, a), EnumMap imap)
+{-# INLINE minViewWithKey #-}
+
+updateMax :: (a -> Maybe a) -> EnumMap k a -> EnumMap k a
+updateMax f = EnumMap . I.updateMax f . unWrap
+{-# INLINE updateMax #-}
+
+updateMin :: (a -> Maybe a) -> EnumMap k a -> EnumMap k a
+updateMin f = EnumMap . I.updateMin f . unWrap
+{-# INLINE updateMin #-}
+
+maxView :: EnumMap k a -> Maybe (a, EnumMap k a)
+maxView = fmap (second EnumMap) . I.maxView . unWrap
+{-# INLINE maxView #-}
+
+minView :: EnumMap k a -> Maybe (a, EnumMap k a)
+minView = fmap (second EnumMap) . I.minView . unWrap
+{-# INLINE minView #-}
+
+deleteFindMax :: (Enum k) => EnumMap k a -> ((k, a), EnumMap k a)
+deleteFindMax = (first toEnum *** EnumMap) . I.deleteFindMax . unWrap
+{-# INLINE deleteFindMax #-}
+
+deleteFindMin :: (Enum k) => EnumMap k a -> ((k, a), EnumMap k a)
+deleteFindMin = (first toEnum *** EnumMap) . I.deleteFindMin . unWrap
+{-# INLINE deleteFindMin #-}
+
+findMin :: (Enum k) => EnumMap k a -> (k, a)
+findMin = first toEnum . I.findMin . unWrap
+{-# INLINE findMin #-}
+
+findMax :: (Enum k) => EnumMap k a -> (k, a)
+findMax = first toEnum . I.findMax . unWrap
+{-# INLINE findMax #-}
+
+deleteMin :: EnumMap k a -> EnumMap k a
+deleteMin = EnumMap . I.deleteMin . unWrap
+{-# INLINE deleteMin #-}
+
+deleteMax :: EnumMap k a -> EnumMap k a
+deleteMax = EnumMap . I.deleteMax . unWrap
+{-# INLINE deleteMax #-}
+
+isProperSubmapOf :: (Eq a) => EnumMap k a -> EnumMap k a -> Bool
+isProperSubmapOf (EnumMap im1) (EnumMap im2) = I.isProperSubmapOf im1 im2
+{-# INLINE isProperSubmapOf #-}
+
+isProperSubmapOfBy :: (a -> b -> Bool) -> EnumMap k a -> EnumMap k b -> Bool
+isProperSubmapOfBy p (EnumMap im1) (EnumMap im2) = I.isProperSubmapOfBy p im1 im2
+{-# INLINE isProperSubmapOfBy #-}
+
+isSubmapOf :: Eq a => EnumMap k a -> EnumMap k a -> Bool
+isSubmapOf (EnumMap im1) (EnumMap im2) = I.isSubmapOf im1 im2
+{-# INLINE isSubmapOf #-}
+
+isSubmapOfBy :: (a -> b -> Bool) -> EnumMap k a -> EnumMap k b -> Bool
+isSubmapOfBy p (EnumMap im1) (EnumMap im2) = I.isSubmapOfBy p im1 im2
+{-# INLINE isSubmapOfBy #-}
+
+map :: (a -> b) -> EnumMap k a -> EnumMap k b
+map f = EnumMap . I.map f . unWrap
+{-# INLINE map #-}
+
+mapWithKey :: (Enum k) => (k -> a -> b) -> EnumMap k a -> EnumMap k b
+mapWithKey f = EnumMap . I.mapWithKey (f . toEnum) . unWrap
+{-# INLINE mapWithKey #-}
+
+traverseWithKey :: (Applicative t, Enum k)
+  => (k -> a -> t b) -> EnumMap k a -> t (EnumMap k b)
+traverseWithKey f = liftA EnumMap . I.traverseWithKey (f . toEnum) . unWrap
+{-# INLINE traverseWithKey #-}
+
+mapAccum :: (a -> b -> (a, c)) -> a -> EnumMap k b -> (a, EnumMap k c)
+mapAccum f a = second EnumMap . I.mapAccum f a . unWrap
+{-# INLINE mapAccum #-}
+
+mapAccumWithKey :: (Enum k)
+  => (a -> k -> b -> (a, c)) -> a -> EnumMap k b -> (a, EnumMap k c)
+mapAccumWithKey f a =
+  second EnumMap . I.mapAccumWithKey (\b -> f b . toEnum) a . unWrap
+{-# INLINE mapAccumWithKey #-}
+
+mapAccumRWithKey :: (Enum k)
+  => (a -> k -> b -> (a, c)) -> a -> EnumMap k b -> (a, EnumMap k c)
+mapAccumRWithKey f a =
+  second EnumMap . I.mapAccumRWithKey (\b -> f b . toEnum) a . unWrap
+{-# INLINE mapAccumRWithKey #-}
+
+mapKeys :: (Enum k) => (k -> k) -> EnumMap k a -> EnumMap k a
+mapKeys f = EnumMap . I.mapKeys (fromEnum . f . toEnum) . unWrap
+{-# INLINE mapKeys #-}
+
+mapKeysWith :: (Enum k) => (a -> a -> a) -> (k -> k) -> EnumMap k a -> EnumMap k a
+mapKeysWith f g = EnumMap . I.mapKeysWith f (fromEnum . g . toEnum) . unWrap
+{-# INLINE mapKeysWith #-}
+
+mapKeysMonotonic :: (Enum k) => (k -> k) -> EnumMap k a -> EnumMap k a
+mapKeysMonotonic f = EnumMap . I.mapKeysMonotonic (fromEnum . f . toEnum) . unWrap
+{-# INLINE mapKeysMonotonic #-}
+
+filter :: (a -> Bool) -> EnumMap k a -> EnumMap k a
+filter p = EnumMap . I.filter p . unWrap
+{-# INLINE filter #-}
+
+filterWithKey :: (Enum k) => (k -> a -> Bool) -> EnumMap k a -> EnumMap k a
+filterWithKey p = EnumMap . I.filterWithKey (p . toEnum) . unWrap
+{-# INLINE filterWithKey #-}
+
+partition :: (a -> Bool) -> EnumMap k a -> (EnumMap k a, EnumMap k a)
+partition p = (EnumMap *** EnumMap) . I.partition p . unWrap
+{-# INLINE partition #-}
+
+partitionWithKey :: (Enum k)
+   => (k -> a -> Bool) -> EnumMap k a -> (EnumMap k a, EnumMap k a)
+partitionWithKey p =
+  (EnumMap *** EnumMap) . I.partitionWithKey (p . toEnum) . unWrap
+{-# INLINE partitionWithKey #-}
+
+mapMaybe :: (a -> Maybe b) -> EnumMap k a -> EnumMap k b
+mapMaybe f = EnumMap . I.mapMaybe f . unWrap
+{-# INLINE mapMaybe #-}
+
+mapMaybeWithKey :: (Enum k) => (k -> a -> Maybe b) -> EnumMap k a -> EnumMap k b
+mapMaybeWithKey f = EnumMap . I.mapMaybeWithKey (f . toEnum) . unWrap
+{-# INLINE mapMaybeWithKey #-}
+
+mapEither :: (a -> Either b c) -> EnumMap k a -> (EnumMap k b, EnumMap k c)
+mapEither f = (EnumMap *** EnumMap) . I.mapEither f . unWrap
+{-# INLINE mapEither #-}
+
+mapEitherWithKey :: (Enum k)
+  => (k -> a -> Either b c) -> EnumMap k a -> (EnumMap k b, EnumMap k c)
+mapEitherWithKey f =
+  (EnumMap *** EnumMap) . I.mapEitherWithKey (f . toEnum) . unWrap
+{-# INLINE mapEitherWithKey #-}
+
+split :: (Enum k) => k -> EnumMap k a -> (EnumMap k a, EnumMap k a)
+split k = (EnumMap *** EnumMap) . I.split (fromEnum k) . unWrap
+{-# INLINE split #-}
+
+splitLookup :: (Enum k) => k -> EnumMap k a -> (EnumMap k a, Maybe a, EnumMap k a)
+splitLookup k = wrap . I.splitLookup (fromEnum k) . unWrap
+  where
+    wrap (im1, ma, im2) = (EnumMap im1, ma, EnumMap im2)
+{-# INLINE splitLookup #-}
+
+foldr :: (Enum k) => (a -> b -> b) -> b -> EnumMap k a -> b
+foldr f a = I.foldr f a . unWrap
+{-# INLINE foldr #-}
+
+foldl :: (Enum k) => (a -> b -> a) -> a -> EnumMap k b -> a
+foldl f a = I.foldl f a . unWrap
+{-# INLINE foldl #-}
+
+foldrWithKey :: (Enum k) => (k -> a -> b -> b) -> b -> EnumMap k a -> b
+foldrWithKey f a = I.foldrWithKey (f . toEnum) a . unWrap
+{-# INLINE foldrWithKey #-}
+
+foldlWithKey :: (Enum k) => (a -> k -> b -> a) -> a -> EnumMap k b -> a
+foldlWithKey f a = I.foldlWithKey (\a' -> f a' . toEnum) a . unWrap
+{-# INLINE foldlWithKey #-}
+
+foldr' :: (Enum k) => (a -> b -> b) -> b -> EnumMap k a -> b
+foldr' f a = I.foldr' f a . unWrap
+{-# INLINE foldr' #-}
+
+foldl' :: (Enum k) => (a -> b -> a) -> a -> EnumMap k b -> a
+foldl' f a = I.foldl' f a . unWrap
+{-# INLINE foldl' #-}
+
+foldrWithKey' :: (Enum k) => (k -> a -> b -> b) -> b -> EnumMap k a -> b
+foldrWithKey' f a = I.foldrWithKey' (f . toEnum) a . unWrap
+{-# INLINE foldrWithKey' #-}
+
+foldlWithKey' :: (Enum k) => (a -> k -> b -> a) -> a -> EnumMap k b -> a
+foldlWithKey' f a = I.foldlWithKey' (\a' -> f a' . toEnum) a . unWrap
+{-# INLINE foldlWithKey' #-}
+
+elems :: EnumMap k a -> [a]
+elems = I.elems . unWrap
+{-# INLINE elems #-}
+
+keys :: (Enum k) => EnumMap k a -> [k]
+keys = P.map toEnum . I.keys . unWrap
+{-# INLINE keys #-}
+
+keysSet :: (Enum k) => EnumMap k a -> EnumSet k
+keysSet = EnumSet.fromDistinctAscList . keys
+{-# INLINE keysSet #-}
+
+fromSet :: (Enum k) => (k -> a) -> EnumSet k -> EnumMap k a
+fromSet f = EnumMap . I.fromSet (f . toEnum) . EnumSet.enumSetToIntSet
+{-# INLINE fromSet #-}
+
+assocs :: (Enum k) => EnumMap k a -> [(k, a)]
+assocs = P.map (first toEnum) . I.assocs . unWrap
+{-# INLINE assocs #-}
+
+toList :: (Enum k) => EnumMap k a -> [(k, a)]
+toList = P.map (first toEnum) . I.toList . unWrap
+{-# INLINE toList #-}
+
+toAscList :: (Enum k) => EnumMap k a -> [(k, a)]
+toAscList = P.map (first toEnum) . I.toAscList . unWrap
+{-# INLINE toAscList #-}
+
+toDescList :: (Enum k) => EnumMap k a -> [(k, a)]
+toDescList = P.map (first toEnum) . I.toDescList . unWrap
+{-# INLINE toDescList #-}
+
+fromList :: (Enum k) => [(k, a)] -> EnumMap k a
+fromList = EnumMap . I.fromList . P.map (first fromEnum)
+{-# INLINE fromList #-}
+
+fromListWith :: (Enum k) => (a -> a -> a) -> [(k, a)] -> EnumMap k a
+fromListWith f = EnumMap . I.fromListWith f . P.map (first fromEnum)
+{-# INLINE fromListWith #-}
+
+fromListWithKey :: (Enum k) => (k -> a -> a -> a) -> [(k, a)] -> EnumMap k a
+fromListWithKey f =
+  EnumMap . I.fromListWithKey (f . toEnum) . P.map (first fromEnum)
+{-# INLINE fromListWithKey #-}
+
+fromAscList :: (Enum k) => [(k, a)] -> EnumMap k a
+fromAscList = EnumMap . I.fromAscList . P.map (first fromEnum)
+{-# INLINE fromAscList #-}
+
+fromAscListWith :: (Enum k) => (a -> a -> a) -> [(k, a)] -> EnumMap k a
+fromAscListWith f = EnumMap . I.fromAscListWith f . P.map (first fromEnum)
+{-# INLINE fromAscListWith #-}
+
+fromAscListWithKey :: (Enum k) => (k -> a -> a -> a) -> [(k, a)] -> EnumMap k a
+fromAscListWithKey f =
+  EnumMap . I.fromAscListWithKey (f . toEnum) . P.map (first fromEnum)
+{-# INLINE fromAscListWithKey #-}
+
+fromDistinctAscList :: (Enum k) => [(k, a)] -> EnumMap k a
+fromDistinctAscList = EnumMap . I.fromDistinctAscList . P.map (first fromEnum)
+{-# INLINE fromDistinctAscList #-}
diff --git a/Data/EnumMap/Lazy.hs b/Data/EnumMap/Lazy.hs
new file mode 100644
--- /dev/null
+++ b/Data/EnumMap/Lazy.hs
@@ -0,0 +1,161 @@
+-- |
+-- Module      :  $Header$
+-- Description :  Data.IntMap.Lazy with Enum keys.
+-- Copyright   :  (c) 2011-2013 Michal Terepeta
+-- License     :  BSD3
+-- Maintainer  :  michal.terepeta@gmail.com
+-- Stability   :  alpha
+-- Portability :  uses DeriveDataTypeable and GeneralizedNewtypeDeriving
+
+-- This is a simple wrapper for 'Data.IntMap.Lazy' that works with any type of
+-- keys that are instances of 'Enum' type class.  For documentation please see
+-- the one for 'Data.IntMap'.
+
+module Data.EnumMap.Lazy
+  ( EnumMap
+
+  -- * Wrapping/unwrapping
+  , intMapToEnumMap
+  , enumMapToIntMap
+
+  -- * Operators
+  , (!)
+  , (\\)
+
+  -- * Query
+  , null
+  , size
+  , member
+  , notMember
+  , lookup
+  , findWithDefault
+  , lookupLT
+  , lookupGT
+  , lookupLE
+  , lookupGE
+
+  -- * Construction
+  , empty
+  , singleton
+
+  -- ** Insertion
+  , insert
+  , insertWith
+  , insertWithKey
+  , insertLookupWithKey
+
+  -- ** Delete\/Update
+  , delete
+  , adjust
+  , adjustWithKey
+  , update
+  , updateWithKey
+  , updateLookupWithKey
+  , alter
+
+  -- * Combine
+
+  -- ** Union
+  , union
+  , unionWith
+  , unionWithKey
+  , unions
+  , unionsWith
+
+  -- ** Difference
+  , difference
+  , differenceWith
+  , differenceWithKey
+
+  -- ** Intersection
+  , intersection
+  , intersectionWith
+  , intersectionWithKey
+
+  -- ** Universal combining function
+  , mergeWithKey
+
+  -- * Traversal
+  -- ** Map
+  , map
+  , mapWithKey
+  , traverseWithKey
+  , mapAccum
+  , mapAccumWithKey
+  , mapAccumRWithKey
+  , mapKeys
+  , mapKeysWith
+  , mapKeysMonotonic
+
+  -- * Folds
+  , foldr
+  , foldl
+  , foldrWithKey
+  , foldlWithKey
+  -- ** Strict folds
+  , foldr'
+  , foldl'
+  , foldrWithKey'
+  , foldlWithKey'
+
+  -- * Conversion
+  , elems
+  , keys
+  , assocs
+  , keysSet
+  , fromSet
+
+  -- ** Lists
+  , toList
+  , fromList
+  , fromListWith
+  , fromListWithKey
+
+  -- ** Ordered lists
+  , toAscList
+  , toDescList
+  , fromAscList
+  , fromAscListWith
+  , fromAscListWithKey
+  , fromDistinctAscList
+
+  -- * Filter
+  , filter
+  , filterWithKey
+  , partition
+  , partitionWithKey
+
+  , mapMaybe
+  , mapMaybeWithKey
+  , mapEither
+  , mapEitherWithKey
+
+  , split
+  , splitLookup
+
+  -- * Submap
+  , isSubmapOf
+  , isSubmapOfBy
+  , isProperSubmapOf
+  , isProperSubmapOfBy
+
+  -- * Min\/Max
+  , findMin
+  , findMax
+  , deleteMin
+  , deleteMax
+  , deleteFindMin
+  , deleteFindMax
+  , updateMin
+  , updateMax
+  , updateMinWithKey
+  , updateMaxWithKey
+  , minView
+  , maxView
+  , minViewWithKey
+  , maxViewWithKey
+  ) where
+
+import Prelude hiding ( filter, foldr, foldl, lookup, map, null )
+
+import Data.EnumMap.Base
diff --git a/Data/EnumMap/Strict.hs b/Data/EnumMap/Strict.hs
new file mode 100644
--- /dev/null
+++ b/Data/EnumMap/Strict.hs
@@ -0,0 +1,414 @@
+-- |
+-- Module      :  $Header$
+-- Description :  Data.IntMap.Strict with Enum keys.
+-- Copyright   :  (c) 2011-2013 Michal Terepeta
+-- License     :  BSD3
+-- Maintainer  :  michal.terepeta@gmail.com
+-- Stability   :  alpha
+-- Portability :  uses DeriveDataTypeable and GeneralizedNewtypeDeriving
+
+-- This is a simple wrapper for 'Data.IntMap.Strict' that works with any type of
+-- keys that are instances of 'Enum' type class.  For documentation please see
+-- the one for 'Data.IntMap'.
+
+module Data.EnumMap.Strict
+  ( EnumMap
+
+  -- * Wrapping/unwrapping
+  , intMapToEnumMap
+  , enumMapToIntMap
+
+  -- * Operators
+  , (!)
+  , (\\)
+
+  -- * Query
+  , null
+  , size
+  , member
+  , notMember
+  , lookup
+  , findWithDefault
+  , lookupLT
+  , lookupGT
+  , lookupLE
+  , lookupGE
+
+  -- * Construction
+  , empty
+  , singleton
+
+  -- ** Insertion
+  , insert
+  , insertWith
+  , insertWithKey
+  , insertLookupWithKey
+
+  -- ** Delete\/Update
+  , delete
+  , adjust
+  , adjustWithKey
+  , update
+  , updateWithKey
+  , updateLookupWithKey
+  , alter
+
+  -- * Combine
+
+  -- ** Union
+  , union
+  , unionWith
+  , unionWithKey
+  , unions
+  , unionsWith
+
+  -- ** Difference
+  , difference
+  , differenceWith
+  , differenceWithKey
+
+  -- ** Intersection
+  , intersection
+  , intersectionWith
+  , intersectionWithKey
+
+  -- ** Universal combining function
+  , mergeWithKey
+
+  -- * Traversal
+  -- ** Map
+  , map
+  , mapWithKey
+  , traverseWithKey
+  , mapAccum
+  , mapAccumWithKey
+  , mapAccumRWithKey
+  , mapKeys
+  , mapKeysWith
+  , mapKeysMonotonic
+
+  -- * Folds
+  , foldr
+  , foldl
+  , foldrWithKey
+  , foldlWithKey
+  -- ** Strict folds
+  , foldr'
+  , foldl'
+  , foldrWithKey'
+  , foldlWithKey'
+
+  -- * Conversion
+  , elems
+  , keys
+  , assocs
+  , keysSet
+  , fromSet
+
+  -- ** Lists
+  , toList
+  , fromList
+  , fromListWith
+  , fromListWithKey
+
+  -- ** Ordered lists
+  , toAscList
+  , toDescList
+  , fromAscList
+  , fromAscListWith
+  , fromAscListWithKey
+  , fromDistinctAscList
+
+  -- * Filter
+  , filter
+  , filterWithKey
+  , partition
+  , partitionWithKey
+
+  , mapMaybe
+  , mapMaybeWithKey
+  , mapEither
+  , mapEitherWithKey
+
+  , split
+  , splitLookup
+
+  -- * Submap
+  , isSubmapOf
+  , isSubmapOfBy
+  , isProperSubmapOf
+  , isProperSubmapOfBy
+
+  -- * Min\/Max
+  , findMin
+  , findMax
+  , deleteMin
+  , deleteMax
+  , deleteFindMin
+  , deleteFindMax
+  , updateMin
+  , updateMax
+  , updateMinWithKey
+  , updateMaxWithKey
+  , minView
+  , maxView
+  , minViewWithKey
+  , maxViewWithKey
+  ) where
+
+import Prelude hiding ( filter, foldr, foldl, lookup, map, null )
+import qualified Prelude as P
+
+import Control.Arrow ( (***), first, second )
+
+import qualified Data.IntMap.Strict as I
+
+import Data.EnumSet ( EnumSet )
+import qualified Data.EnumSet as EnumSet
+
+import Data.EnumMap.Base hiding
+  ( findWithDefault
+  , singleton
+  , insert
+  , insertWith
+  , insertWithKey
+  , insertLookupWithKey
+  , adjust
+  , adjustWithKey
+  , update
+  , updateWithKey
+  , updateLookupWithKey
+  , alter
+  , unionsWith
+  , unionWith
+  , unionWithKey
+  , differenceWith
+  , differenceWithKey
+  , intersectionWith
+  , intersectionWithKey
+  , mergeWithKey
+  , updateMinWithKey
+  , updateMaxWithKey
+  , updateMax
+  , updateMin
+  , map
+  , mapWithKey
+  , mapAccum
+  , mapAccumWithKey
+  , mapAccumRWithKey
+  , mapKeysWith
+  , mapMaybe
+  , mapMaybeWithKey
+  , mapEither
+  , mapEitherWithKey
+  , fromSet
+  , fromList
+  , fromListWith
+  , fromListWithKey
+  , fromAscList
+  , fromAscListWith
+  , fromAscListWithKey
+  , fromDistinctAscList
+  )
+
+findWithDefault :: (Enum k) => a -> k -> EnumMap k a -> a
+findWithDefault def k = I.findWithDefault def (fromEnum k) . unWrap
+{-# INLINE findWithDefault #-}
+
+singleton :: (Enum k) => k -> a -> EnumMap k a
+singleton k = EnumMap . I.singleton (fromEnum k)
+{-# INLINE singleton #-}
+
+insert :: (Enum k) => k -> a -> EnumMap k a -> EnumMap k a
+insert k a = EnumMap . I.insert (fromEnum k) a . unWrap
+{-# INLINE insert #-}
+
+insertWith :: (Enum k) => (a -> a -> a) -> k -> a -> EnumMap k a -> EnumMap k a
+insertWith f k a = EnumMap . I.insertWith f (fromEnum k) a . unWrap
+{-# INLINE insertWith #-}
+
+insertWithKey :: (Enum k)
+  => (k -> a -> a -> a) -> k -> a -> EnumMap k a -> EnumMap k a
+insertWithKey f k a =
+  EnumMap . I.insertWithKey (f . toEnum) (fromEnum k) a . unWrap
+{-# INLINE insertWithKey #-}
+
+insertLookupWithKey :: (Enum k)
+  => (k -> a -> a -> a) -> k -> a -> EnumMap k a -> (Maybe a, EnumMap k a)
+insertLookupWithKey f k a =
+  second EnumMap . I.insertLookupWithKey (f . toEnum) (fromEnum k) a . unWrap
+{-# INLINE insertLookupWithKey #-}
+
+adjust ::  (Enum k) => (a -> a) -> k -> EnumMap k a -> EnumMap k a
+adjust f k = EnumMap . I.adjust f (fromEnum k) . unWrap
+{-# INLINE adjust #-}
+
+adjustWithKey :: (Enum k) => (k -> a -> a) -> k -> EnumMap k a -> EnumMap k a
+adjustWithKey f k = EnumMap . I.adjustWithKey (f . toEnum) (fromEnum k) . unWrap
+{-# INLINE adjustWithKey #-}
+
+alter :: (Enum k) => (Maybe a -> Maybe a) -> k -> EnumMap k a -> EnumMap k a
+alter f k = EnumMap . I.alter f (fromEnum k) . unWrap
+{-# INLINE alter #-}
+
+unionsWith :: (a -> a -> a) -> [EnumMap k a] -> EnumMap k a
+unionsWith f = EnumMap . I.unionsWith f . P.map unWrap
+{-# INLINE unionsWith #-}
+
+unionWith :: (a -> a -> a) -> EnumMap k a -> EnumMap k a -> EnumMap k a
+unionWith f (EnumMap im1) (EnumMap im2) = EnumMap $ I.unionWith f im1 im2
+{-# INLINE unionWith #-}
+
+unionWithKey :: (Enum k)
+  => (k -> a -> a -> a) -> EnumMap k a -> EnumMap k a -> EnumMap k a
+unionWithKey f (EnumMap im1) (EnumMap im2) =
+  EnumMap $ I.unionWithKey (f . toEnum) im1 im2
+{-# INLINE unionWithKey #-}
+
+differenceWith :: (a -> b -> Maybe a) -> EnumMap k a -> EnumMap k b -> EnumMap k a
+differenceWith f (EnumMap im1) (EnumMap im2) =
+  EnumMap $ I.differenceWith f im1 im2
+{-# INLINE differenceWith #-}
+
+differenceWithKey :: (Enum k)
+  => (k -> a -> b -> Maybe a) -> EnumMap k a -> EnumMap k b -> EnumMap k a
+differenceWithKey f (EnumMap im1) (EnumMap im2) =
+  EnumMap $ I.differenceWithKey (f . toEnum) im1 im2
+{-# INLINE differenceWithKey #-}
+
+intersectionWith :: (a -> b -> c) -> EnumMap k a -> EnumMap k b -> EnumMap k c
+intersectionWith f (EnumMap im1) (EnumMap im2) =
+  EnumMap $ I.intersectionWith f im1 im2
+{-# INLINE intersectionWith #-}
+
+intersectionWithKey :: (Enum k)
+  => (k -> a -> b -> c) -> EnumMap k a -> EnumMap k b -> EnumMap k c
+intersectionWithKey f (EnumMap im1) (EnumMap im2) =
+  EnumMap $ I.intersectionWithKey (f . toEnum) im1 im2
+{-# INLINE intersectionWithKey #-}
+
+mergeWithKey :: (Enum k)
+  => (k -> a -> b -> Maybe c)
+  -> (EnumMap k a -> EnumMap k c)
+  -> (EnumMap k b -> EnumMap k c)
+  -> EnumMap k a
+  -> EnumMap k b
+  -> EnumMap k c
+mergeWithKey f ga gb = \ma mb -> EnumMap $
+  I.mergeWithKey (f . toEnum)
+                 (unWrap . ga . EnumMap)
+                 (unWrap . gb . EnumMap)
+                 (unWrap ma)
+                 (unWrap mb)
+{-# INLINE mergeWithKey #-}
+
+update ::  (Enum k) => (a -> Maybe a) -> k -> EnumMap k a -> EnumMap k a
+update f k = EnumMap . I.update f (fromEnum k) . unWrap
+{-# INLINE update #-}
+
+updateWithKey ::  (Enum k)
+  => (k -> a -> Maybe a) -> k -> EnumMap k a -> EnumMap k a
+updateWithKey f k = EnumMap . I.updateWithKey (f . toEnum) (fromEnum k) . unWrap
+{-# INLINE updateWithKey #-}
+
+updateLookupWithKey ::  (Enum k)
+  => (k -> a -> Maybe a) -> k -> EnumMap k a -> (Maybe a,EnumMap k a)
+updateLookupWithKey f k =
+  second EnumMap . I.updateLookupWithKey (f . toEnum) (fromEnum k) . unWrap
+{-# INLINE updateLookupWithKey #-}
+
+updateMinWithKey :: (Enum k) => (k -> a -> Maybe a) -> EnumMap k a -> EnumMap k a
+updateMinWithKey f = EnumMap . I.updateMinWithKey (f . toEnum) . unWrap
+{-# INLINE updateMinWithKey #-}
+
+updateMaxWithKey :: (Enum k) => (k -> a -> Maybe a) -> EnumMap k a -> EnumMap k a
+updateMaxWithKey f = EnumMap . I.updateMaxWithKey (f . toEnum) . unWrap
+{-# INLINE updateMaxWithKey #-}
+
+updateMax :: (a -> Maybe a) -> EnumMap k a -> EnumMap k a
+updateMax f = EnumMap . I.updateMax f . unWrap
+{-# INLINE updateMax #-}
+
+updateMin :: (a -> Maybe a) -> EnumMap k a -> EnumMap k a
+updateMin f = EnumMap . I.updateMin f . unWrap
+{-# INLINE updateMin #-}
+
+map :: (a -> b) -> EnumMap k a -> EnumMap k b
+map f = EnumMap . I.map f . unWrap
+{-# INLINE map #-}
+
+mapWithKey :: (Enum k) => (k -> a -> b) -> EnumMap k a -> EnumMap k b
+mapWithKey f = EnumMap . I.mapWithKey (f . toEnum) . unWrap
+{-# INLINE mapWithKey #-}
+
+mapAccum :: (a -> b -> (a, c)) -> a -> EnumMap k b -> (a, EnumMap k c)
+mapAccum f a = second EnumMap . I.mapAccum f a . unWrap
+{-# INLINE mapAccum #-}
+
+mapAccumWithKey :: (Enum k)
+  => (a -> k -> b -> (a, c)) -> a -> EnumMap k b -> (a, EnumMap k c)
+mapAccumWithKey f a =
+  second EnumMap . I.mapAccumWithKey (\b -> f b . toEnum) a . unWrap
+{-# INLINE mapAccumWithKey #-}
+
+mapAccumRWithKey :: (Enum k)
+  => (a -> k -> b -> (a, c)) -> a -> EnumMap k b -> (a, EnumMap k c)
+mapAccumRWithKey f a =
+  second EnumMap . I.mapAccumRWithKey (\b -> f b . toEnum) a . unWrap
+{-# INLINE mapAccumRWithKey #-}
+
+mapKeysWith :: (Enum k) => (a -> a -> a) -> (k -> k) -> EnumMap k a -> EnumMap k a
+mapKeysWith f g = EnumMap . I.mapKeysWith f (fromEnum . g . toEnum) . unWrap
+{-# INLINE mapKeysWith #-}
+
+mapMaybe :: (a -> Maybe b) -> EnumMap k a -> EnumMap k b
+mapMaybe f = EnumMap . I.mapMaybe f . unWrap
+{-# INLINE mapMaybe #-}
+
+mapMaybeWithKey :: (Enum k) => (k -> a -> Maybe b) -> EnumMap k a -> EnumMap k b
+mapMaybeWithKey f = EnumMap . I.mapMaybeWithKey (f . toEnum) . unWrap
+{-# INLINE mapMaybeWithKey #-}
+
+mapEither :: (a -> Either b c) -> EnumMap k a -> (EnumMap k b, EnumMap k c)
+mapEither f = (EnumMap *** EnumMap) . I.mapEither f . unWrap
+{-# INLINE mapEither #-}
+
+mapEitherWithKey :: (Enum k)
+  => (k -> a -> Either b c) -> EnumMap k a -> (EnumMap k b, EnumMap k c)
+mapEitherWithKey f =
+  (EnumMap *** EnumMap) . I.mapEitherWithKey (f . toEnum) . unWrap
+{-# INLINE mapEitherWithKey #-}
+
+fromSet :: (Enum k) => (k -> a) -> EnumSet k -> EnumMap k a
+fromSet f = EnumMap . I.fromSet (f . toEnum) . EnumSet.enumSetToIntSet
+{-# INLINE fromSet #-}
+
+fromList :: (Enum k) => [(k, a)] -> EnumMap k a
+fromList = EnumMap . I.fromList . P.map (first fromEnum)
+{-# INLINE fromList #-}
+
+fromListWith :: (Enum k) => (a -> a -> a) -> [(k, a)] -> EnumMap k a
+fromListWith f = EnumMap . I.fromListWith f . P.map (first fromEnum)
+{-# INLINE fromListWith #-}
+
+fromListWithKey :: (Enum k) => (k -> a -> a -> a) -> [(k, a)] -> EnumMap k a
+fromListWithKey f =
+  EnumMap . I.fromListWithKey (f . toEnum) . P.map (first fromEnum)
+{-# INLINE fromListWithKey #-}
+
+fromAscList :: (Enum k) => [(k, a)] -> EnumMap k a
+fromAscList = EnumMap . I.fromAscList . P.map (first fromEnum)
+{-# INLINE fromAscList #-}
+
+fromAscListWith :: (Enum k) => (a -> a -> a) -> [(k, a)] -> EnumMap k a
+fromAscListWith f = EnumMap . I.fromAscListWith f . P.map (first fromEnum)
+{-# INLINE fromAscListWith #-}
+
+fromAscListWithKey :: (Enum k) => (k -> a -> a -> a) -> [(k, a)] -> EnumMap k a
+fromAscListWithKey f =
+  EnumMap . I.fromAscListWithKey (f . toEnum) . P.map (first fromEnum)
+{-# INLINE fromAscListWithKey #-}
+
+fromDistinctAscList :: (Enum k) => [(k, a)] -> EnumMap k a
+fromDistinctAscList = EnumMap . I.fromDistinctAscList . P.map (first fromEnum)
+{-# INLINE fromDistinctAscList #-}
diff --git a/Data/EnumSet.hs b/Data/EnumSet.hs
--- a/Data/EnumSet.hs
+++ b/Data/EnumSet.hs
@@ -1,14 +1,14 @@
-{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveDataTypeable         #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 
 -- |
 -- Module      :  $Header$
 -- Description :  Data.IntSet with Enum elements.
--- Copyright   :  (c) 2011 Michal Terepeta
+-- Copyright   :  (c) 2011-2013 Michal Terepeta
 -- License     :  BSD3
 -- Maintainer  :  michal.terepeta@gmail.com
 -- Stability   :  alpha
--- Portability :  uses GeneralizedNewtypeDeriving
+-- Portability :  uses DeriveDataTypeable and GeneralizedNewtypeDeriving
 
 -- This is a simple wrapper for 'Data.IntSet' that allows storing any elements
 -- of Enum type class. Useful if one wants to have the performance of
@@ -30,6 +30,10 @@
   , size
   , member
   , notMember
+  , lookupLT
+  , lookupGT
+  , lookupLE
+  , lookupGE
   , isSubsetOf
   , isProperSubsetOf
 
@@ -54,9 +58,16 @@
   -- * Map
   , map
 
-  -- * Fold
+  -- * Folds
+  , foldr
+  , foldl
+  -- ** Strict folds
+  , foldr'
+  , foldl'
+  -- ** Legacy folds
   , fold
 
+
   -- * Min\/Max
   , findMin
   , findMax
@@ -76,30 +87,34 @@
 
   -- ** Ordered list
   , toAscList
+  , toDescList
   , fromAscList
   , fromDistinctAscList
+
   ) where
 
-import Prelude hiding ( filter, lookup, map, null )
+import Prelude hiding ( filter, foldl, foldr, lookup, map, null )
 import qualified Prelude as P
 
 import Data.IntSet ( IntSet )
 import qualified Data.IntSet as I
 
+import Control.Arrow ( (***) )
+import Control.DeepSeq ( NFData )
 import Data.Monoid ( Monoid )
 import Data.Typeable ( Typeable )
 
 import Text.Read
 
 -- | Wrapper for 'IntSet' with 'Enum' elements.
-newtype EnumSet e = EnumSet { unWrap :: IntSet }
-  deriving (Eq, Monoid, Ord, Typeable)
+newtype EnumSet k = EnumSet { unWrap :: IntSet }
+  deriving (Eq, Monoid, Ord, Typeable, NFData)
 
-instance (Enum e, Show e) => Show (EnumSet e) where
-  showsPrec p es = showParen (p > 10) $
-    showString "fromList " . shows (toList es)
+instance (Enum k, Show k) => Show (EnumSet k) where
+  showsPrec p ks = showParen (p > 10) $
+    showString "fromList " . shows (toList ks)
 
-instance (Enum e, Read e) => Read (EnumSet e) where
+instance (Enum k, Read k) => Read (EnumSet k) where
   readPrec = parens . prec 10 $ do
     Ident "fromList" <- lexP
     list <- readPrec
@@ -110,167 +125,193 @@
 --
 
 -- | Wrap 'IntSet'.
-intSetToEnumSet :: IntSet -> EnumSet e
+intSetToEnumSet :: IntSet -> EnumSet k
 intSetToEnumSet = EnumSet
+{-# INLINE intSetToEnumSet #-}
 
 -- | Unwrap 'IntSet'.
-enumSetToIntSet :: EnumSet e -> IntSet
+enumSetToIntSet :: EnumSet k -> IntSet
 enumSetToIntSet = unWrap
-
---
--- A few useful functions used through the module; not exported.
---
-
-pairWrap :: (IntSet, IntSet) -> (EnumSet e, EnumSet e)
-pairWrap (is1, is2) = (EnumSet is1, EnumSet is2)
-{-# INLINE pairWrap #-}
-
-toEnumWrap :: (Enum e) => (Int, IntSet) -> (e, EnumSet e)
-toEnumWrap (i, is) = (toEnum i, EnumSet is)
-{-# INLINE toEnumWrap #-}
+{-# INLINE enumSetToIntSet #-}
 
 --
 -- Here begins the main part.
 --
 
-(\\) :: EnumSet e -> EnumSet e -> EnumSet e
+(\\) :: EnumSet k -> EnumSet k -> EnumSet k
 (EnumSet is1) \\ (EnumSet is2) = EnumSet $ is1 I.\\ is2
 {-# INLINE (\\) #-}
 
-null :: EnumSet e -> Bool
+null :: EnumSet k -> Bool
 null = I.null . unWrap
 {-# INLINE null #-}
 
-size :: EnumSet e -> Int
+size :: EnumSet k -> Int
 size = I.size . unWrap
 {-# INLINE size #-}
 
-member :: (Enum e) => e -> EnumSet e -> Bool
-member e = I.member (fromEnum e) . unWrap
+member :: (Enum k) => k -> EnumSet k -> Bool
+member k = I.member (fromEnum k) . unWrap
 {-# INLINE member #-}
 
-notMember :: (Enum e) => e -> EnumSet e -> Bool
-notMember e = I.notMember (fromEnum e) . unWrap
+notMember :: (Enum k) => k -> EnumSet k -> Bool
+notMember k = I.notMember (fromEnum k) . unWrap
 {-# INLINE notMember #-}
 
-empty :: EnumSet e
+lookupLT :: (Enum k) => k -> EnumSet k -> Maybe k
+lookupLT k = fmap toEnum . I.lookupLT (fromEnum k) . unWrap
+{-# INLINE lookupLT #-}
+
+lookupGT :: (Enum k) => k -> EnumSet k -> Maybe k
+lookupGT k = fmap toEnum . I.lookupGT (fromEnum k) . unWrap
+{-# INLINE lookupGT #-}
+
+lookupLE :: (Enum k) => k -> EnumSet k -> Maybe k
+lookupLE k = fmap toEnum . I.lookupLE (fromEnum k) . unWrap
+{-# INLINE lookupLE #-}
+
+lookupGE :: (Enum k) => k -> EnumSet k -> Maybe k
+lookupGE k = fmap toEnum . I.lookupGE (fromEnum k) . unWrap
+{-# INLINE lookupGE #-}
+
+empty :: EnumSet k
 empty = EnumSet I.empty
 {-# INLINE empty #-}
 
-singleton :: (Enum e) => e -> EnumSet e
+singleton :: (Enum k) => k -> EnumSet k
 singleton = EnumSet . I.singleton . fromEnum
 {-# INLINE singleton #-}
 
-insert :: (Enum e) => e -> EnumSet e -> EnumSet e
-insert e = EnumSet . I.insert (fromEnum e) . unWrap
+insert :: (Enum k) => k -> EnumSet k -> EnumSet k
+insert k = EnumSet . I.insert (fromEnum k) . unWrap
 {-# INLINE insert #-}
 
-delete :: (Enum e) => e -> EnumSet e -> EnumSet e
-delete e = EnumSet . I.delete (fromEnum e) . unWrap
+delete :: (Enum k) => k -> EnumSet k -> EnumSet k
+delete k = EnumSet . I.delete (fromEnum k) . unWrap
 {-# INLINE delete #-}
 
-unions :: [EnumSet e] -> EnumSet e
+unions :: [EnumSet k] -> EnumSet k
 unions = EnumSet . I.unions . P.map unWrap
 {-# INLINE unions #-}
 
-union :: EnumSet e -> EnumSet e -> EnumSet e
+union :: EnumSet k -> EnumSet k -> EnumSet k
 union (EnumSet is1) (EnumSet is2) = EnumSet $ I.union is1 is2
 {-# INLINE union #-}
 
-difference :: EnumSet e -> EnumSet e -> EnumSet e
+difference :: EnumSet k -> EnumSet k -> EnumSet k
 difference (EnumSet is1) (EnumSet is2) = EnumSet $ I.difference is1 is2
 {-# INLINE difference #-}
 
-intersection :: EnumSet e -> EnumSet e -> EnumSet e
+intersection :: EnumSet k -> EnumSet k -> EnumSet k
 intersection (EnumSet is1) (EnumSet is2) = EnumSet $ I.intersection is1 is2
 {-# INLINE intersection #-}
 
-isProperSubsetOf :: EnumSet e -> EnumSet e -> Bool
+isProperSubsetOf :: EnumSet k -> EnumSet k -> Bool
 isProperSubsetOf (EnumSet is1) (EnumSet is2) = I.isProperSubsetOf is1 is2
 {-# INLINE isProperSubsetOf #-}
 
-isSubsetOf :: EnumSet e -> EnumSet e -> Bool
+isSubsetOf :: EnumSet k -> EnumSet k -> Bool
 isSubsetOf (EnumSet is1) (EnumSet is2) = I.isSubsetOf is1 is2
 {-# INLINE isSubsetOf #-}
 
-filter :: (Enum e) => (e -> Bool) -> EnumSet e -> EnumSet e
+filter :: (Enum k) => (k -> Bool) -> EnumSet k -> EnumSet k
 filter f = EnumSet . I.filter (f . toEnum) . unWrap
 {-# INLINE filter #-}
 
-partition :: (Enum e) => (e -> Bool) -> EnumSet e -> (EnumSet e, EnumSet e)
-partition f = pairWrap . I.partition (f . toEnum) . unWrap
+partition :: (Enum k) => (k -> Bool) -> EnumSet k -> (EnumSet k, EnumSet k)
+partition f = (EnumSet *** EnumSet) . I.partition (f . toEnum) . unWrap
 {-# INLINE partition #-}
 
-split :: (Enum e) => e -> EnumSet e -> (EnumSet e, EnumSet e)
-split e = pairWrap . I.split (fromEnum e) . unWrap
+split :: (Enum k) => k -> EnumSet k -> (EnumSet k, EnumSet k)
+split k = (EnumSet *** EnumSet) . I.split (fromEnum k) . unWrap
 {-# INLINE split #-}
 
-splitMember :: (Enum e) => e -> EnumSet e -> (EnumSet e, Bool, EnumSet e)
-splitMember e =  wrap . I.splitMember (fromEnum e) . unWrap
+splitMember :: (Enum k) => k -> EnumSet k -> (EnumSet k, Bool, EnumSet k)
+splitMember k =  wrap . I.splitMember (fromEnum k) . unWrap
   where
     wrap (is1, b, is2) = (EnumSet is1, b, EnumSet is2)
 {-# INLINE splitMember #-}
 
-maxView :: (Enum e) => EnumSet e -> Maybe (e, EnumSet e)
-maxView = fmap toEnumWrap . I.maxView . unWrap
+maxView :: (Enum k) => EnumSet k -> Maybe (k, EnumSet k)
+maxView = fmap (toEnum *** EnumSet) . I.maxView . unWrap
 {-# INLINE maxView #-}
 
-minView :: (Enum e) => EnumSet e -> Maybe (e, EnumSet e)
-minView = fmap toEnumWrap . I.minView  . unWrap
+minView :: (Enum k) => EnumSet k -> Maybe (k, EnumSet k)
+minView = fmap (toEnum *** EnumSet) . I.minView  . unWrap
 {-# INLINE minView #-}
 
-deleteFindMin :: (Enum e) => EnumSet e -> (e, EnumSet e)
-deleteFindMin = toEnumWrap  . I.deleteFindMin . unWrap
+deleteFindMin :: (Enum k) => EnumSet k -> (k, EnumSet k)
+deleteFindMin = (toEnum *** EnumSet) . I.deleteFindMin . unWrap
 {-# INLINE deleteFindMin #-}
 
-deleteFindMax :: (Enum e) => EnumSet e -> (e, EnumSet e)
-deleteFindMax = toEnumWrap . I.deleteFindMax . unWrap
+deleteFindMax :: (Enum k) => EnumSet k -> (k, EnumSet k)
+deleteFindMax = (toEnum *** EnumSet) . I.deleteFindMax . unWrap
 {-# INLINE deleteFindMax #-}
 
-findMin :: (Enum e) => EnumSet e -> e
+findMin :: (Enum k) => EnumSet k -> k
 findMin = toEnum . I.findMin . unWrap
 {-# INLINE findMin #-}
 
-findMax :: (Enum e) => EnumSet e -> e
+findMax :: (Enum k) => EnumSet k -> k
 findMax = toEnum . I.findMax . unWrap
 {-# INLINE findMax #-}
 
-deleteMin :: EnumSet e -> EnumSet e
+deleteMin :: EnumSet k -> EnumSet k
 deleteMin = EnumSet . I.deleteMin . unWrap
 {-# INLINE deleteMin #-}
 
-deleteMax :: EnumSet e -> EnumSet e
+deleteMax :: EnumSet k -> EnumSet k
 deleteMax = EnumSet . I.deleteMax . unWrap
 {-# INLINE deleteMax #-}
 
-map :: (Enum e) => (e -> e) -> EnumSet e -> EnumSet e
+map :: (Enum k) => (k -> k) -> EnumSet k -> EnumSet k
 map f = EnumSet . I.map (fromEnum . f . toEnum) . unWrap
 {-# INLINE map #-}
 
-fold :: (Enum e) => (e -> b -> b) -> b -> EnumSet e -> b
+foldr :: (Enum k) => (k -> b -> b) -> b -> EnumSet k -> b
+foldr f acc = I.foldr (f . toEnum) acc . unWrap
+{-# INLINE foldr #-}
+
+foldl :: (Enum k) => (a -> k -> a) -> a -> EnumSet k -> a
+foldl f acc = I.foldl (\a -> f a . toEnum) acc . unWrap
+{-# INLINE foldl #-}
+
+foldr' :: (Enum k) => (k -> b -> b) -> b -> EnumSet k -> b
+foldr' f acc = I.foldr' (f . toEnum) acc . unWrap
+{-# INLINE foldr' #-}
+
+foldl' :: (Enum k) => (a -> k -> a) -> a -> EnumSet k -> a
+foldl' f acc = I.foldl' (\a -> f a . toEnum) acc . unWrap
+{-# INLINE foldl' #-}
+
+fold :: (Enum k) => (k -> b -> b) -> b -> EnumSet k -> b
 fold f acc = I.fold (f . toEnum) acc . unWrap
 {-# INLINE fold #-}
 
-elems :: (Enum e) => EnumSet e -> [e]
+elems :: (Enum k) => EnumSet k -> [k]
 elems = P.map toEnum . I.elems . unWrap
 {-# INLINE elems #-}
 
-toList :: (Enum e) => EnumSet e -> [e]
+toList :: (Enum k) => EnumSet k -> [k]
 toList = P.map toEnum . I.toList . unWrap
 {-# INLINE toList #-}
 
-toAscList :: (Enum e) => EnumSet e -> [e]
+toAscList :: (Enum k) => EnumSet k -> [k]
 toAscList = P.map toEnum . I.toAscList . unWrap
 {-# INLINE toAscList #-}
 
-fromList :: (Enum e) => [e] -> EnumSet e
+toDescList :: (Enum k) => EnumSet k -> [k]
+toDescList = P.map toEnum . I.toDescList . unWrap
+{-# INLINE toDescList #-}
+
+fromList :: (Enum k) => [k] -> EnumSet k
 fromList = EnumSet . I.fromList . P.map fromEnum
 {-# INLINE fromList #-}
 
-fromAscList :: (Enum e) => [e] -> EnumSet e
+fromAscList :: (Enum k) => [k] -> EnumSet k
 fromAscList = EnumSet . I.fromAscList . P.map fromEnum
 {-# INLINE fromAscList #-}
 
-fromDistinctAscList :: (Enum e) => [e] -> EnumSet e
+fromDistinctAscList :: (Enum k) => [k] -> EnumSet k
 fromDistinctAscList = EnumSet . I.fromDistinctAscList . P.map fromEnum
 {-# INLINE fromDistinctAscList #-}
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c)2011, Michal Terepeta
+Copyright (c) 2011-2013 Michal Terepeta
 
 All rights reserved.
 
diff --git a/enummapset.cabal b/enummapset.cabal
--- a/enummapset.cabal
+++ b/enummapset.cabal
@@ -1,5 +1,5 @@
 name:           enummapset
-version:        0.2.0
+version:        0.5.2.0
 synopsis:       IntMap and IntSet with Enum keys/elements.
 description:    This package contains simple wrappers around 'Data.IntMap' and
                 'Data.IntSet' with 'Enum' keys and elements respectively.
@@ -10,7 +10,7 @@
 license-file:   LICENSE
 author:         Michal Terepeta
 maintainer:     Michal Terepeta <michal.terepeta@gmail.com>
-copyright:      (c) 2011 Michal Terepeta
+copyright:      (c) 2011-2013 Michal Terepeta
 
 category:       Data
 build-type:     Simple
@@ -21,13 +21,24 @@
   type:         git
   location:     https://github.com/michalt/enummapset.git
 
+flag debug
+  description:  Debug build (more warnings, etc.)
+  default:      False
+
 Library
   exposed-modules:
     Data.EnumMap
+    Data.EnumMap.Lazy
+    Data.EnumMap.Strict
     Data.EnumSet
 
+  other-modules:
+    Data.EnumMap.Base
+
   build-depends:
     base < 5,
-    containers >= 0.5 && < 0.6
+    containers >= 0.5.2 && < 0.6,
+    deepseq
 
-  ghc-options: -Wall
+  if flag(debug)
+    ghc-options: -Wall
