[project @ 2005-03-15 13:38:27 by simonmar]
[ghc-base.git] / Data / FiniteMap.hs
index a44bb36..8bafafc 100644 (file)
@@ -2,20 +2,22 @@
 -- |
 -- Module      :  Data.FiniteMap
 -- Copyright   :  (c) The University of Glasgow 2001
--- License     :  BSD-style (see the file libraries/core/LICENSE)
+-- License     :  BSD-style (see the file libraries/base/LICENSE)
 -- 
 -- Maintainer  :  libraries@haskell.org
 -- Stability   :  provisional
 -- Portability :  portable
 --
+-- NOTE: Data.FiniteMap is DEPRECATED, please use "Data.Map" instead.
+--
 -- A finite map implementation, derived from the paper:
---        S Adams, "Efficient sets: a balancing act"
+--        /Efficient sets: a balancing act/, S. Adams,
 --        Journal of functional programming 3(4) Oct 1993, pp553-562
 --
--- ToDo: clean up, remove the COMPILING_GHC stuff.
---
 -----------------------------------------------------------------------------
 
+-- ToDo: clean up, remove the COMPILING_GHC stuff.
+
 -- The code is SPECIALIZEd to various highly-desirable types (e.g., Id)
 -- near the end (only \tr{#ifdef COMPILING_GHC}).
 
 #define OUTPUTABLE_key {--}
 #endif
 
-module Data.FiniteMap (
+module Data.FiniteMap
+  {-# DEPRECATED "Please use Data.Map instead." #-} 
+  (
+       -- * The @FiniteMap@ type
        FiniteMap,              -- abstract type
 
+       -- * Construction
        emptyFM, unitFM, listToFM,
 
+       -- * Lookup operations
+       lookupFM, lookupWithDefaultFM,
+       elemFM,
+
+       -- * Adding elements
        addToFM,
        addToFM_C,
        addListToFM,
        addListToFM_C,
+
+       -- * Deleting elements
        IF_NOT_GHC(delFromFM COMMA)
        delListFromFM,
 
+       -- * Combination
        plusFM,
        plusFM_C,
+
+       -- * Extracting information
+       fmToList, keysFM, eltsFM,
+       sizeFM, isEmptyFM,
+
+       -- * Other operations
        minusFM,
        foldFM,
-
        IF_NOT_GHC(intersectFM COMMA)
        IF_NOT_GHC(intersectFM_C COMMA)
        IF_NOT_GHC(mapFM COMMA filterFM COMMA)
 
-       sizeFM, isEmptyFM, elemFM, lookupFM, lookupWithDefaultFM,
+       foldFM_GE, fmToList_GE, keysFM_GE, eltsFM_GE,
+       foldFM_LE, fmToList_LE, keysFM_LE, eltsFM_LE,
 
-       fmToList, keysFM, eltsFM
+        minFM, maxFM,
 
 #ifdef COMPILING_GHC
        , bagToFM
 #endif
     ) where
 
-import Prelude
+import Prelude -- necessary to get dependencies right
 
 import Data.Maybe ( isJust )
 #ifdef __GLASGOW_HASKELL__
 import GHC.Base
+import Data.Typeable
+import Data.Generics.Basics
+import Data.Generics.Instances
+#endif
+
+#ifdef __HADDOCK__
+import Prelude
 #endif
 
 #ifdef COMPILING_GHC
@@ -97,54 +124,81 @@ import Bag ( foldBag )
 #endif /* not GHC */
 
 
+
 -- ---------------------------------------------------------------------------
 -- The signature of the module
 
---     BUILDING
+-- | An empty 'FiniteMap'.
 emptyFM                :: FiniteMap key elt
+
+-- | A 'FiniteMap' containing a single mapping
 unitFM         :: key -> elt -> FiniteMap key elt
+
+-- | Makes a 'FiniteMap' from a list of @(key,value)@ pairs. In the
+-- case of duplicates, the last is taken
 listToFM       :: (Ord key OUTPUTABLE_key) => [(key,elt)] -> FiniteMap key elt
-                       -- In the case of duplicates, the last is taken
+
 #ifdef COMPILING_GHC
 bagToFM                :: (Ord key OUTPUTABLE_key) => Bag (key,elt) -> FiniteMap key elt
                        -- In the case of duplicates, who knows which is taken
 #endif
 
 --     ADDING AND DELETING
-                  -- Throws away any previous binding
-                  -- In the list case, the items are added starting with the
-                  -- first one in the list
+
+-- | Adds an element to a 'FiniteMap'.  Any previous mapping with the same
+-- key is overwritten.
 addToFM                :: (Ord key OUTPUTABLE_key) => FiniteMap key elt -> key -> elt  -> FiniteMap key elt
+
+-- | Adds a list of elements to a 'FiniteMap', in the order given in
+-- the list.  Overwrites previous mappings.
 addListToFM    :: (Ord key OUTPUTABLE_key) => FiniteMap key elt -> [(key,elt)] -> FiniteMap key elt
 
                   -- Combines with previous binding
                   -- In the combining function, the first argument is the "old" element,
                   -- while the second is the "new" one.
+
+-- | Adds an element to a 'FiniteMap'.  If there is already an element
+-- with the same key, then the specified combination function is used
+-- to calculate the new value. The already present element is passed as
+-- the first argument and the new element to add as second.
 addToFM_C      :: (Ord key OUTPUTABLE_key) => (elt -> elt -> elt)
                           -> FiniteMap key elt -> key -> elt
                           -> FiniteMap key elt
+
+-- | A list version of 'addToFM_C'.  The elements are added in the
+-- order given in the list.
 addListToFM_C  :: (Ord key OUTPUTABLE_key) => (elt -> elt -> elt)
                           -> FiniteMap key elt -> [(key,elt)]
                           -> FiniteMap key elt
 
-                  -- Deletion doesn't complain if you try to delete something
-                  -- which isn't there
+-- | Deletes an element from a 'FiniteMap'.  If there is no element with
+-- the specified key, then the original 'FiniteMap' is returned.
 delFromFM      :: (Ord key OUTPUTABLE_key) => FiniteMap key elt -> key   -> FiniteMap key elt
+
+-- | List version of 'delFromFM'.
 delListFromFM  :: (Ord key OUTPUTABLE_key) => FiniteMap key elt -> [key] -> FiniteMap key elt
 
---     COMBINING
-                  -- Bindings in right argument shadow those in the left
+-- | Combine two 'FiniteMap's.  Mappings in the second argument shadow
+-- those in the first.
 plusFM         :: (Ord key OUTPUTABLE_key) => FiniteMap key elt -> FiniteMap key elt
                           -> FiniteMap key elt
 
-                  -- Combines bindings for the same thing with the given function
+-- | Combine two 'FiniteMap's.  The specified combination function is
+-- used to calculate the new value when there are two elements with
+-- the same key.
 plusFM_C       :: (Ord key OUTPUTABLE_key) => (elt -> elt -> elt)
                           -> FiniteMap key elt -> FiniteMap key elt -> FiniteMap key elt
 
-minusFM                :: (Ord key OUTPUTABLE_key) => FiniteMap key elt -> FiniteMap key elt -> FiniteMap key elt
-                  -- (minusFM a1 a2) deletes from a1 any bindings which are bound in a2
+-- | @(minusFM a1 a2)@ deletes from @a1@ any mappings which are bound in @a2@
+minusFM                :: (Ord key OUTPUTABLE_key) => FiniteMap key elt1 -> FiniteMap key elt2 -> FiniteMap key elt1
 
+-- | @(intersectFM a1 a2)@ returns a new 'FiniteMap' containing
+-- mappings from @a1@ for which @a2@ also has a mapping with the same
+-- key.
 intersectFM    :: (Ord key OUTPUTABLE_key) => FiniteMap key elt -> FiniteMap key elt -> FiniteMap key elt
+
+-- | Returns the intersection of two mappings, using the specified
+-- combination function to combine values.
 intersectFM_C  :: (Ord key OUTPUTABLE_key) => (elt1 -> elt2 -> elt3)
                           -> FiniteMap key elt1 -> FiniteMap key elt2 -> FiniteMap key elt3
 
@@ -158,16 +212,37 @@ filterFM  :: (Ord key OUTPUTABLE_key) => (key -> elt -> Bool)
 sizeFM         :: FiniteMap key elt -> Int
 isEmptyFM      :: FiniteMap key elt -> Bool
 
+-- | Returns 'True' if the specified @key@ has a mapping in this
+-- 'FiniteMap', or 'False' otherwise.
 elemFM         :: (Ord key OUTPUTABLE_key) => key -> FiniteMap key elt -> Bool
+
+-- | Looks up a key in a 'FiniteMap', returning @'Just' v@ if the key
+-- was found with value @v@, or 'Nothing' otherwise.
 lookupFM       :: (Ord key OUTPUTABLE_key) => FiniteMap key elt -> key -> Maybe elt
+
+-- | Looks up a key in a 'FiniteMap', returning @elt@ if the specified
+-- @key@ was not found.
 lookupWithDefaultFM
                :: (Ord key OUTPUTABLE_key) => FiniteMap key elt -> elt -> key -> elt
                -- lookupWithDefaultFM supplies a "default" elt
                -- to return for an unmapped key
 
 --     LISTIFYING
+
+-- | Convert a 'FiniteMap' to a @[(key, elt)]@ sorted by 'Ord' key
+--
 fmToList       :: FiniteMap key elt -> [(key,elt)]
+
+-- | Extract the keys from a 'FiniteMap', in the order of the keys, so
+--
+-- > keysFM == map fst . fmToList
+--
 keysFM         :: FiniteMap key elt -> [key]
+
+-- | Extract the elements from a 'FiniteMap', in the order of the keys, so
+--
+-- > eltsFM == map snd . fmToList
+--
 eltsFM         :: FiniteMap key elt -> [elt]
 
 -- ---------------------------------------------------------------------------
@@ -185,6 +260,7 @@ eltsFM              :: FiniteMap key elt -> [elt]
 -- * size of left subtree is differs from size of right subtree by a
 --   factor of at most \tr{sIZE_RATIO}
 
+-- | A mapping from @key@s to @elt@s.
 data FiniteMap key elt
   = EmptyFM
   | Branch key elt             -- Key and elt stored here
@@ -201,7 +277,7 @@ emptyFM
     bottom = panic "emptyFM"
 -}
 
--- #define EmptyFM (Branch _ _ IF_GHC(0#,0) _ _)
+--  #define EmptyFM (Branch _ _ IF_GHC(0#,0) _ _)
 
 unitFM key elt = Branch key elt IF_GHC(1#,1) emptyFM emptyFM
 
@@ -211,6 +287,28 @@ listToFM = addListToFM emptyFM
 bagToFM = foldBag plusFM (\ (k,v) -> unitFM k v) emptyFM
 #endif
 
+instance (Show k, Show e) => Show (FiniteMap k e) where
+  showsPrec p m = showsPrec p (fmToList m)
+
+instance Functor (FiniteMap k) where
+  fmap f = mapFM (const f)
+
+#if __GLASGOW_HASKELL__
+
+#include "Typeable.h"
+INSTANCE_TYPEABLE2(FiniteMap,arrayTc,"FiniteMap")
+
+-- This instance preserves data abstraction at the cost of inefficiency.
+-- We omit reflection services for the sake of data abstraction.
+
+instance (Data a, Data b, Ord a) => Data (FiniteMap a b) where
+  gfoldl f z fm = z listToFM `f` (fmToList fm)
+  toConstr _    = error "toConstr"
+  gunfold _ _   = error "gunfold"
+  dataTypeOf _  = mkNorepType "Data.FiniteMap.FiniteMap"
+
+#endif
+
 
 -- ---------------------------------------------------------------------------
 -- Adding to and deleting from @FiniteMaps@
@@ -373,6 +471,77 @@ eltsFM fm   = foldFM (\ key elt rest -> elt : rest)       [] fm
 
 
 -- ---------------------------------------------------------------------------
+-- Bulk operations on all keys >= or <=        a certain threshold
+
+-- | Fold through all elements greater than or equal to the supplied key,
+-- in increasing order.
+foldFM_GE       :: Ord key => (key -> elt -> a -> a) -> a -> key ->
+   FiniteMap key elt -> a
+
+foldFM_GE k z fr EmptyFM = z
+foldFM_GE k z fr (Branch key elt _ fm_l fm_r)
+  | key >= fr = foldFM_GE k (k key elt (foldFM_GE k z fr fm_r)) fr fm_l
+  | otherwise = foldFM_GE k z fr fm_r
+
+-- | List elements greater than or equal to the supplied key, in increasing
+-- order
+fmToList_GE      :: Ord key => FiniteMap key elt -> key ->  [(key,elt)]
+fmToList_GE fm fr = foldFM_GE (\ key elt rest -> (key,elt) : rest) [] fr fm
+
+-- | List keys greater than or equal to the supplied key, in increasing order
+keysFM_GE       :: Ord key => FiniteMap key elt -> key -> [key]
+keysFM_GE fm fr  = foldFM_GE (\ key elt rest -> key : rest)       [] fr fm
+
+-- | List elements corresponding to keys greater than or equal to the supplied
+-- key, in increasing order of key.
+eltsFM_GE       :: Ord key => FiniteMap key elt -> key -> [elt]
+eltsFM_GE fm fr  = foldFM_GE (\ key elt rest -> elt : rest)       [] fr fm
+
+-- | Fold through all elements less than or equal to the supplied key,
+-- in decreasing order.
+foldFM_LE       :: Ord key => (key -> elt -> a -> a) -> a -> key ->
+   FiniteMap key elt -> a
+foldFM_LE k z fr EmptyFM = z
+foldFM_LE k z fr (Branch key elt _ fm_l fm_r)
+  | key <= fr = foldFM_LE k (k key elt (foldFM_LE k z fr fm_l)) fr fm_r
+  | otherwise = foldFM_LE k z fr fm_l
+
+-- | List elements greater than or equal to the supplied key, in decreasing
+-- order
+fmToList_LE      :: Ord key => FiniteMap key elt -> key ->  [(key,elt)]
+fmToList_LE fm fr = foldFM_LE (\ key elt rest -> (key,elt) : rest) [] fr fm
+
+-- | List keys greater than or equal to the supplied key, in decreasing order
+keysFM_LE       :: Ord key => FiniteMap key elt -> key -> [key]
+keysFM_LE fm fr  = foldFM_LE (\ key elt rest -> key : rest)       [] fr fm
+
+-- | List elements corresponding to keys greater than or equal to the supplied
+-- key, in decreasing order of key.
+eltsFM_LE       :: Ord key => FiniteMap key elt -> key -> [elt]
+eltsFM_LE fm fr  = foldFM_LE (\ key elt rest -> elt : rest)       [] fr fm
+
+-- ---------------------------------------------------------------------------
+-- Getting minimum and maximum key out.
+-- ---------------------------------------------------------------------------
+
+-- | Extract minimum key, or Nothing if the map is empty.
+minFM :: Ord key => FiniteMap key elt -> Maybe key
+minFM EmptyFM = Nothing
+minFM (Branch key _ _ fm_l _) =
+   case minFM fm_l of
+      Nothing -> Just key
+      Just key1 -> Just key1
+
+-- | Extract maximum key, or Nothing if the map is empty.
+maxFM :: Ord key => FiniteMap key elt -> Maybe key
+maxFM EmptyFM = Nothing
+maxFM (Branch key _ _ _ fm_r) =
+   case maxFM fm_r of
+      Nothing -> Just key
+      Just key1 -> Just key1
+
+
+-- ---------------------------------------------------------------------------
 -- The implementation of balancing
 
 -- Basic construction of a @FiniteMap@:
@@ -730,4 +899,4 @@ instance (Ord key, Ord elt) => Ord (FiniteMap key elt) where
     IF_NCG(COMMA   (elt -> elt -> elt) -> FiniteMap Reg elt -> FiniteMap Reg elt -> FiniteMap Reg elt)
     #-}
 
-#endif {- compiling for GHC -}
+#endif /* compiling for GHC */