diff --git a/grid.cabal b/grid.cabal
--- a/grid.cabal
+++ b/grid.cabal
@@ -1,5 +1,5 @@
 Name:              grid
-Version:           7.6.10
+Version:           7.7.0
 Stability:         experimental
 Synopsis:          Tools for working with regular grids (graphs, lattices).
 Description:       Provides tools for working with regular arrangements
@@ -12,7 +12,7 @@
 Category:          Math
 License:           BSD3
 License-file:      LICENSE
-Copyright:         (c) Amy de Buitl&eacute;ir 2010-2014
+Copyright:         (c) Amy de Buitl&eacute;ir 2010-2015
 Homepage:          https://github.com/mhwombat/grid
 Bug-reports:       https://github.com/mhwombat/grid/issues
 Author:            Amy de Buitl&eacute;ir
@@ -27,7 +27,7 @@
 source-repository this
   type:     git
   location: https://github.com/mhwombat/grid.git
-  tag:      7.6.10
+  tag:      7.7.0
 
 
 library
@@ -54,6 +54,7 @@
 test-suite grid-tests
   type:            exitcode-stdio-1.0
   build-depends:   base ==4.*,
+                   containers ==0.5.*,
                    test-framework-quickcheck2 ==0.3.*,
                    QuickCheck ==2.7.*,
                    test-framework ==0.8.*,
diff --git a/src/Math/Geometry/Grid.hs b/src/Math/Geometry/Grid.hs
--- a/src/Math/Geometry/Grid.hs
+++ b/src/Math/Geometry/Grid.hs
@@ -1,7 +1,7 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.Grid
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/Math/Geometry/Grid/Hexagonal.hs b/src/Math/Geometry/Grid/Hexagonal.hs
--- a/src/Math/Geometry/Grid/Hexagonal.hs
+++ b/src/Math/Geometry/Grid/Hexagonal.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.HexGrid
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/Math/Geometry/Grid/Hexagonal2.hs b/src/Math/Geometry/Grid/Hexagonal2.hs
--- a/src/Math/Geometry/Grid/Hexagonal2.hs
+++ b/src/Math/Geometry/Grid/Hexagonal2.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.HexGrid
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/Math/Geometry/Grid/HexagonalInternal.hs b/src/Math/Geometry/Grid/HexagonalInternal.hs
--- a/src/Math/Geometry/Grid/HexagonalInternal.hs
+++ b/src/Math/Geometry/Grid/HexagonalInternal.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.HexGridInternal
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/Math/Geometry/Grid/HexagonalInternal2.hs b/src/Math/Geometry/Grid/HexagonalInternal2.hs
--- a/src/Math/Geometry/Grid/HexagonalInternal2.hs
+++ b/src/Math/Geometry/Grid/HexagonalInternal2.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.HexGridInternal
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/Math/Geometry/Grid/Octagonal.hs b/src/Math/Geometry/Grid/Octagonal.hs
--- a/src/Math/Geometry/Grid/Octagonal.hs
+++ b/src/Math/Geometry/Grid/Octagonal.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.OctGrid
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/Math/Geometry/Grid/OctagonalInternal.hs b/src/Math/Geometry/Grid/OctagonalInternal.hs
--- a/src/Math/Geometry/Grid/OctagonalInternal.hs
+++ b/src/Math/Geometry/Grid/OctagonalInternal.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.OctGridInternal
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/Math/Geometry/Grid/Square.hs b/src/Math/Geometry/Grid/Square.hs
--- a/src/Math/Geometry/Grid/Square.hs
+++ b/src/Math/Geometry/Grid/Square.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.SquareGrid
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/Math/Geometry/Grid/SquareInternal.hs b/src/Math/Geometry/Grid/SquareInternal.hs
--- a/src/Math/Geometry/Grid/SquareInternal.hs
+++ b/src/Math/Geometry/Grid/SquareInternal.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.SquareGridInternal
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/Math/Geometry/Grid/Triangular.hs b/src/Math/Geometry/Grid/Triangular.hs
--- a/src/Math/Geometry/Grid/Triangular.hs
+++ b/src/Math/Geometry/Grid/Triangular.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.TriGrid
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/Math/Geometry/Grid/TriangularInternal.hs b/src/Math/Geometry/Grid/TriangularInternal.hs
--- a/src/Math/Geometry/Grid/TriangularInternal.hs
+++ b/src/Math/Geometry/Grid/TriangularInternal.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.TriGridInternal
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/Math/Geometry/GridInternal.hs b/src/Math/Geometry/GridInternal.hs
--- a/src/Math/Geometry/GridInternal.hs
+++ b/src/Math/Geometry/GridInternal.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.GridInternal
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/Math/Geometry/GridMap.hs b/src/Math/Geometry/GridMap.hs
--- a/src/Math/Geometry/GridMap.hs
+++ b/src/Math/Geometry/GridMap.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.GridMap
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
@@ -11,7 +11,6 @@
 -- This module is a wrapper around @'Math.Geometry.Grid'@ and 
 -- @'Data.Map'@, in order to combine the functionality of grids and maps
 -- into a single type.
---
 ------------------------------------------------------------------------
 {-# LANGUAGE TypeFamilies, FlexibleContexts, MultiParamTypeClasses #-}
 
@@ -38,9 +37,14 @@
 
 -- | A regular arrangement of tiles, having a value associated with
 --   each tile.
---   Minimal complete definition: @toMap@, @toGrid@, @adjustWithKey@,
---   @mapWithKey@.
+--   Minimal complete definition: @toMap@, @toGrid@, @insertWithKey@,
+--   @delete@, @adjustWithKey@, @alter@, @mapWithKey@, @filterWithKey@.
 --
+--   Once a @'GridMap'@ is created, the underlying grid is /fixed/;
+--   tiles cannot be added or removed. However, values can be added
+--   to empty tiles, and the value at a tile can be modified or
+--   removed.
+--
 --   Note: Some of the methods have an @Ord@ constraint on the grid 
 --   index. This is purely to make it easier to write implementations.
 --   While tile positions can be ordered (e.g., @(1,2) < (2,1)@), the
@@ -56,172 +60,368 @@
   type BaseGrid gm v
 
   -- | Find the value at a tile position in the grid.
+  --   Calls error if the tile is not in the grid, or if the tile does
+  --   not have an associated value.
+  --
+  -- > λ> let m = lazyGridMap (rectSquareGrid 1 2) ["red","blue"]
+  -- > λ> m ! (0,0)
+  -- > "red"
+  -- > λ> m ! (0,5)
+  -- > "*** Exception: Map.!: given key is not an element in the map
   (!) :: (k ~ (G.Index (BaseGrid gm v)), Ord k) => gm v -> k -> v
   (!) gm k = toMap gm M.! k
 
-  -- | Returns a map of grid indices to values.
+  -- | Returns a map of tile positions to values.
+  --
+  -- > λ> toMap $ lazyGridMap (rectSquareGrid 1 2) ["red", "blue"]
+  -- > fromList [((0,0),"red"),((1,0),"blue")]
   toMap :: k ~ (G.Index (BaseGrid gm v)) => gm v -> M.Map k v
 
   -- | Returns the grid on which this map is based.
+  --
+  -- > λ> toGrid $ lazyGridMap (rectSquareGrid 1 2) ["red", "blue"]
+  -- > rectSquareGrid 1 2
   toGrid :: gm v -> BaseGrid gm v
 
   -- | Convert the map to a list of key/value pairs.
+  --
+  -- > λ> toList $ lazyGridMap (rectSquareGrid 1 2) ["red", "blue"]
+  -- > [((0,0),"red"),((1,0),"blue")]
   toList :: k ~ (G.Index (BaseGrid gm v)) => gm v -> [(k, v)]
   toList = M.toList . toMap
 
-  -- | Lookup the value at a tile position in the grid map.
+  -- | The expression @'lookup' k m@ returns the value contained in the
+  --   tile at position @k@ in the map @m@.
+  --   If the tile does not contain a value, or is outside the map
+  --   bounds, @Nothing@ is returned.
+  --
+  -- > λ> let m = lazyGridMap (rectSquareGrid 1 2) ["red","blue"]
+  -- > λ> Math.Geometry.GridMap.lookup (1,0) m
+  -- > Just "blue"
+  -- > λ> Math.Geometry.GridMap.lookup (5,5) m
+  -- > Nothing
   lookup :: (k ~ (G.Index (BaseGrid gm v)), Ord k) => k -> gm v -> Maybe v
   lookup k = M.lookup k . toMap
 
-  -- | Adjust a value at a specific tile position. When the tile is not
-  --   within the bounds of the grid map, the original grid map is
-  --   returned.
+  -- | Insert a new value at a tile position in the grid map.
+  --   If the tile already contains a value, the value is replaced.
+  --
+  -- > λ> insert (1,0) "hello" $ lazyGridMap (rectSquareGrid 1 2) ["red"]
+  -- > lazyGridMap (rectSquareGrid 1 2) ["red","hello"]
+  -- > λ> insert (1,0) "hello" $ lazyGridMap (rectSquareGrid 1 2) ["red","blue"]
+  -- > lazyGridMap (rectSquareGrid 1 2) ["red","hello"]
+  -- > λ> insert (5,5) "hello" $ lazyGridMap (rectSquareGrid 1 2) ["red","blue"]
+  -- > lazyGridMap (rectSquareGrid 1 2) ["red","blue"]
+  insert :: (k ~ (G.Index (BaseGrid gm v)), Ord k) => k -> v -> gm v -> gm v
+  insert = insertWith const
+
+  -- | The expression @'insertWith' f k v m@ will insert the value
+  --   @v@ into the tile at position @k@ if the tile does not already
+  --   contain a value.
+  --   If the tile does contain a value, it is replaced with
+  --   @f v old_value@.
+  --   If the tile is not within the bounds of the grid map,
+  --   the original grid map is returned.
+  --
+  -- > λ> let m = lazyGridMap (rectSquareGrid 1 2) [100]
+  -- > λ> insertWith (+) (0,0) 1 m
+  -- > lazyGridMap (rectSquareGrid 1 2) [101]
+  -- > λ> insertWith (+) (1,0) 1 m
+  -- > lazyGridMap (rectSquareGrid 1 2) [100,1]
+  -- > λ> insertWith (+) (5,5) 1 m
+  -- > lazyGridMap (rectSquareGrid 1 2) [100]
+  insertWith :: (k ~ (G.Index (BaseGrid gm v)), Ord k) =>
+    (v -> v -> v) -> k -> v -> gm v -> gm v
+  insertWith f = insertWithKey (\_ x' y' -> f x' y')
+
+  -- | The expression @'insertWithKey' f k v m@ will insert the value
+  --   @v@ into the tile at position @k@ if the tile does not already
+  --   contain a value.
+  --   If the tile does contain a value, it is replaced with
+  --   @f k v old_value@.
+  --   If the tile is not within the bounds of the grid map,
+  --   the original grid map is returned.
+  --
+  -- > λ> let m = lazyGridMap (rectSquareGrid 1 2) ["red"]
+  -- > λ> let f k x y = show k ++ " " ++ x ++ y
+  -- > λ> insertWithKey f (0,0) "dark" m
+  -- > lazyGridMap (rectSquareGrid 1 2) ["(0,0) darkred"]
+  -- > λ> insertWithKey f (1,0) "dark" m
+  -- > lazyGridMap (rectSquareGrid 1 2) ["red","dark"]
+  -- > λ> insertWithKey f (5,5) "dark" m
+  -- > lazyGridMap (rectSquareGrid 1 2) ["red"]
+  insertWithKey :: (k ~ (G.Index (BaseGrid gm v)), Ord k) =>
+    (k -> v -> v -> v) -> k -> v -> gm v -> gm v
+
+  -- | Combines @'lookup'@ with @'insertWithKey'@.
+  --   The old value is returned, along with the updated map.
+  insertLookupWithKey :: (k ~ (G.Index (BaseGrid gm v)), Ord k) =>
+    (k -> v -> v -> v) -> k -> v -> gm v -> (Maybe v, gm v)
+  insertLookupWithKey f k v gm = (lookup k gm, insertWithKey f k v gm)
+
+  -- | Deletes the value at a tile position in the grid map.
+  --   The tile is not removed from the grid.
+  --   If the tile is not within the bounds of the grid map,
+  --   the original grid map is returned.
+  --   Note: Although this function may remove values, it never removes
+  --   tiles from the underlying grid.
+  --
+  -- > λ> let m = lazyGridMap (rectSquareGrid 1 2) ["red"]
+  -- > λ> delete (0,0) m
+  -- > lazyGridMap (rectSquareGrid 1 2) []
+  -- > λ> delete (1,0) m
+  -- > lazyGridMap (rectSquareGrid 1 2) ["red"]
+  -- > λ> delete (5,5) m
+  -- > lazyGridMap (rectSquareGrid 1 2) ["red"]
+  delete :: (k ~ (G.Index (BaseGrid gm v)), Ord k) => k -> gm v -> gm v
+
+  -- | Adjust a value at a specific tile position.
+  --   If the tile does not contain a value,
+  --   or is not within the bounds of the grid map,
+  --   the original grid map is returned.
+  --
+  -- > λ> let m = lazyGridMap (rectSquareGrid 1 2) ["world"]
+  -- > λ> let f x = "hello " ++ x
+  -- > λ> adjust f (0,0) m
+  -- > lazyGridMap (rectSquareGrid 1 2) ["hello world"]
+  -- > λ> adjust f (1,0) m
+  -- > lazyGridMap (rectSquareGrid 1 2) ["world"]
+  -- > λ> adjust f (5,5) m
+  -- > lazyGridMap (rectSquareGrid 1 2) ["world"]
   adjust :: (k ~ (G.Index (BaseGrid gm v)), Ord k) => 
     (v -> v) -> k -> gm v -> gm v
   adjust f = adjustWithKey (\_ v -> f v)
 
-  -- | Adjust a value at a specific tile position. When the tile is not
+  -- | Adjust a value at a specific tile position. If the tile is not
   --   within the bounds of the grid map, the original grid map is
   --   returned.
+  --
+  -- > λ> let m = lazyGridMap (rectSquareGrid 1 2) ["world"]
+  -- > λ> let f k x = "Hello, " ++ x ++ " from " ++ show k
+  -- > λ> adjustWithKey f (0,0) m
+  -- > lazyGridMap (rectSquareGrid 1 2) ["Hello, world from (0,0)"]
+  -- > λ> adjustWithKey f (1,0) m
+  -- > lazyGridMap (rectSquareGrid 1 2) ["world"]
+  -- > λ> adjustWithKey f (5,5) m
+  -- > lazyGridMap (rectSquareGrid 1 2) ["world"]
   adjustWithKey :: (k ~ (G.Index (BaseGrid gm v)), Ord k) => 
     (k -> v -> v) -> k -> gm v -> gm v
 
+  -- | The expression (alter f k map) alters the value at k, or absence
+  --   thereof.
+  --   If the tile is not within the bounds of the grid map,
+  --   the original grid map is returned.
+  --   Can be used to insert, delete, or update a value.
+  --   Note: Although this function may remove values, it never removes
+  --   tiles from the underlying grid.
+  --
+  -- > λ> let m = lazyGridMap (rectSquareGrid 1 2) ["red"]
+  -- > λ> let f _ = Nothing
+  -- > λ> alter f (1,0) m
+  -- > lazyGridMap (rectSquareGrid 1 2) ["red"]
+  -- > λ> alter f (0,0) m -- deleting a value
+  -- > lazyGridMap (rectSquareGrid 1 2) []
+  -- > λ> alter f (5,5) m
+  -- > lazyGridMap (rectSquareGrid 1 2) ["red"]
+  -- > λ> let f _ = Just "hi!"
+  -- > λ> alter f (1,0) m -- inserting a value
+  -- > lazyGridMap (rectSquareGrid 1 2) ["red","hi!"]
+  -- > λ> alter f (0,0) m -- updating a value
+  -- > lazyGridMap (rectSquareGrid 1 2) ["hi!"]
+  -- > λ> alter f (5,5) m
+  -- > lazyGridMap (rectSquareGrid 1 2) ["red"]
+  alter :: (k ~ (G.Index (BaseGrid gm v)), Ord k) =>
+    (Maybe v -> Maybe v) -> k -> gm v -> gm v
+
   -- | The expression @('findWithDefault' def k map)@ returns the value
   --   at tile position @k@ or returns @def@ when the tile is not within
   --   the bounds of the grid map.
+  --
+  -- > λ> let m = lazyGridMap (rectSquareGrid 1 2) ["red"]
+  -- > λ> findWithDefault "yellow" (0,0) m
+  -- > "red"
+  -- > λ> findWithDefault "yellow" (1,0) m
+  -- > "yellow"
+  -- > λ> findWithDefault "yellow" (5,5) m
+  -- > "yellow"
   findWithDefault :: (k ~ (G.Index (BaseGrid gm v)), Ord k) => 
     v -> k -> gm v -> v
   findWithDefault v k = M.findWithDefault v k . toMap
 
-  -- | Returns all values in the map 
+  -- | Returns the position of all tiles in the map that contain a
+  --   value.
+  --   To get a list of all tiles in the map regardless of whether or
+  --   not they contain values, use @'Math.Geometry.Grid.indices'@.
+  keys :: (k ~ (G.Index (BaseGrid gm v)), Ord k) => gm v -> [k]
+  keys = M.keys . toMap
+  
+  -- | Returns all values in the map.
   elems :: gm v -> [v]
   elems = M.elems . toMap
 
-  -- | Map a function over all values in the map.
+  -- | Maps a function over all values in the map.
+  --
+  -- > λ> Math.Geometry.GridMap.map (++ "!") $ lazyGridMap (rectSquareGrid 1 3) ["red","blue"]
+  -- > lazyGridMap (rectSquareGrid 1 3) ["red!","blue!"]
   map 
     :: (GridMap gm v2, 
         G.Index (BaseGrid gm v) ~ G.Index (BaseGrid gm v2)) => 
     (v -> v2) -> gm v -> gm v2
   map f = mapWithKey (\_ v -> f v)
 
-  -- | Map a function over all values in the map.
+  -- | Maps a function over all values in the map.
+  --
+  -- > λ> let f k v = v ++ "@" ++ show k
+  -- > λ> mapWithKey f $ lazyGridMap (rectSquareGrid 1 3) ["red","blue"]
+  -- > lazyGridMap (rectSquareGrid 1 3) ["red@(0,0)","blue@(1,0)"]
   mapWithKey 
     :: (k ~ G.Index (BaseGrid gm v), k ~ G.Index (BaseGrid gm v2), 
         GridMap gm v2) => 
       (k -> v -> v2) -> gm v -> gm v2
 
+  -- | Return a map containing only the values that satisfy the
+  --   predicate.
+  --   Note: Although this function may remove values, it never removes
+  --   tiles from the underlying grid.
+  --
+  --
+  -- > λ> Math.Geometry.GridMap.filter (> 100) $ lazyGridMap (rectSquareGrid 1 4) [99, 100, 101, 102]
+  -- > lazyGridMap (rectSquareGrid 1 4) [101,102]
+  filter :: (v -> Bool) -> gm v -> gm v
+  filter p = filterWithKey (\_ x -> p x)
+    
+  -- | Return a map containing only the values that satisfy the
+  --   predicate, which may depend on a tile's index as well as its
+  --   value.
+  --   Note: Although this function may remove values, it never removes
+  --   tiles from the underlying grid.
+  --
+  -- > λ> let f k v = k > (2,0) && v > 100
+  -- > λ> filterWithKey f $ lazyGridMap (rectSquareGrid 1 4) [99, 100, 101, 102]
+  -- > lazyGridMap (rectSquareGrid 1 4) [102]
+  filterWithKey
+    :: k ~ (G.Index (BaseGrid gm v)) =>
+      (k -> v -> Bool) -> gm v -> gm v
+
 {- $Compare
-Some functions in @Data.Map@ have been replaced in @GridMap@.
-These changes are listed in the table below.
+Some functions in @Data.Map@ are not currently implemented in @GridMap@.
+These differences are listed in the table below.
 
 @
 Map function        | corresponding GridMap function
 --------------------+----------------------------------------------
 !                   | !
-\\\\                  | See note 1
-empty               | 'Math.Geometry.GridMap.Lazy.lazyGridMap' g []
-findWithDefault     | 'findWithDefault'
-insert              | See notes 1, 2
-lookup              | 'lookup'
-lookupLE            | See notes 1, 3
-lookupLT            | See notes 1, 3
-lookupGE            | See notes 1, 3
-lookupGT            | See notes 1, 3
-member              | 'Math.Geometry.Grid.contains'
-notMember           | not 'Math.Geometry.Grid.contains'
-null                | 'Math.Geometry.Grid.null'
-singleton           | 'lazyGridMap' g [v]
-size                | 'Math.Geometry.Grid.size', 'Math.Geometry.Grid.tileCount'
-insert              | See notes 1, 2
-insertWith          | See notes 1, 2
-insertWithKey       | See notes 1, 2
-insertLookupWithKey | See notes 1, 2
-delete              | See notes 1, 2
+\\\\                  | See notes 1, 2
 adjust              | 'adjust'
 adjustWithKey       | 'adjustWithKey'
-update              | See notes 1, 2
-updateWithKey       | See notes 1, 2
-updateLookupWithKey | See notes 1, 2
-alter               | See notes 1, 2
-union               | See notes 1, 2
-unionWith           | See notes 1, 2
-unionWithKey        | See notes 1, 2
-unions              | See notes 1, 2
-unionsWith          | See notes 1, 2
-difference          | See notes 1, 2
-differenceWith      | See notes 1, 2
-differenceWithKey   | See notes 1, 2
-intersection        | See notes 1, 2
-intersectionWith    | See notes 1, 2
-intersectionWithKey | See notes 1, 2
-mergeWithKey        | See notes 1, 2
-M.map               | 'Math.Geometry.GridMap.Lazy.fmap', or see note 1
-mapWithKey          | See note 1
-traverseWithKey     | See notes 1, 2
-mapAccum            | See note 1
-mapAccumWithKey     | See note 1
-mapAccumRWithKey    | See note 1
-mapKeys             | See note 1
-mapKeysWith         | See note 1
-mapKeysMonotonic    | See note 1
-foldr               | See note 1
+alter               | 'alter'
+assocs              | See note 1
+delete              | 'delete'
+deleteAt            | See note 3
+deleteFindMax       | See note 3
+deleteFindMin       | See note 3
+deleteMax           | See note 3
+deleteMin           | See note 3
+difference          | See notes 1, 4
+differenceWith      | See notes 1, 4
+differenceWithKey   | See notes 1, 4
+elemAt              | See notes 1, 3
+elems               | 'elems'
+empty               | 'empty'
+filter              | 'filter'
+filterWithKey       | 'filterWithKey'
+findIndex           | See notes 1, 3
+findMax             | See notes 1, 3
+findMin             | See notes 1, 3
+findWithDefault     | 'findWithDefault'
 foldl               | See note 1
-foldrWithKey        | See note 1
+foldl'              | See note 1
 foldlWithKey        | See note 1
+foldlWithKey'       | See note 1
+foldr               | See note 1
 foldr'              | See note 1
-foldl'              | See note 1
+foldrWithKey        | See note 1
 foldrWithKey'       | See note 1
-foldlWithKey'       | See note 1
-elems               | 'elems'
-keys                | 'indices'
-assocs              | See note 1
-keysSet             | See note 1
-fromSet             | 'Math.Geometry.GridMap.Lazy.lazyGridMap'
-toList              | See note 1
-fromList            | 'Math.Geometry.GridMap.Lazy.lazyGridMap'
-fromListWithKey     | 'Math.Geometry.GridMap.Lazy.lazyGridMap'
-fromListWith        | 'Math.Geometry.GridMap.Lazy.lazyGridMap'
-toAscList           | See notes 1, 3
-toDescList          | See notes 1, 3
 fromAscList         | See notes 1, 3
 fromAscListWith     | See notes 1, 3
 fromAscListWithKey  | See notes 1, 3
 fromDistinctAscList | See notes 1, 3
-filter              | See notes 1, 2
-filterWithKey       | See notes 1, 2
-partition           | See notes 1, 2
-partitionWithKey    | See notes 1, 2
-mapMaybe            | See notes 1, 2
-mapMaybeWithKey     | See notes 1, 2
-mapEither           | See notes 1, 2
-mapEitherWithKey    | See notes 1, 2
-split               | See notes 1, 2
-splitLookup         | See notes 1, 2
-isSubmapOf          | See note 1
-isSubmapOfBy        | See note 1
+fromList            | 'Math.Geometry.GridMap.Lazy.lazyGridMap'
+fromListWith        | 'Math.Geometry.GridMap.Lazy.lazyGridMap'
+fromListWithKey     | 'Math.Geometry.GridMap.Lazy.lazyGridMap'
+fromSet             | 'Math.Geometry.GridMap.Lazy.lazyGridMap'
+insert              | 'insert'
+insertLookupWithKey | 'insertLookupWithKey'
+insertWith          | 'insertWith'
+insertWithKey       | 'insertWithKey'
+intersection        | See notes 1, 2
+intersectionWithKey | See notes 1, 2
+intersectionWith    | See notes 1, 2
 isProperSubmapOf    | See note 1
 isProperSubmapOfBy  | See note 1
-lookupIndex         | See note 1
-findIndex           | See note 1
-elemAt              | See note 1
-updateAt            | See note 1
-deleteAt            | See notes 1, 2
-findMin             | See notes 1, 3
-findMax             | See notes 1, 3
-deleteMin           | See notes 1, 2, 3
-deleteMax           | See notes 1, 2, 3
-deleteFindMin       | See notes 1, 2, 3
-deleteFindMax       | See notes 1, 2, 3
-updateMin           | See notes 1, 2, 3
-updateMax           | See notes 1, 2, 3
-updateMinWithKey    | See notes 1, 2, 3
-updateMaxWithKey    | See notes 1, 2, 3
-minView             | See notes 1, 3
+isSubmapOf          | See note 1
+isSubmapOfBy        | See note 1
+keys                | 'indices'
+keysSet             | See note 1
+lookup              | 'lookup'
+lookupGE            | See notes 1, 3
+lookupGT            | See notes 1, 3
+lookupIndex         | See notes 1, 3
+lookupLE            | See notes 1, 3
+lookupLT            | See notes 1, 3
+map                 | 'map'
+mapAccum            | See notes 1, 3
+mapAccumRWithKey    | See notes 1, 3
+mapAccumWithKey     | See notes 1, 3
+mapEither           | See note 1
+mapEitherWithKey    | See note 1
+mapKeys             | See notes 1, 2
+mapKeysMonotonic    | See notes 1, 2
+mapKeysWith         | See notes 1, 2
+mapMaybe            | See note 1
+mapMaybeWithKey     | See note 1
+mapWithKey          | 'mapWithKey'
 maxView             | See notes 1, 3
-minViewWithKey      | See notes 1, 2, 3
-maxViewWithKey      | See notes 1, 2, 3
+maxViewWithKey      | See notes 1, 3
+member              | 'Math.Geometry.Grid.contains'
+mergeWithKey        | See notes 1, 2
+minView             | See notes 1, 3
+minViewWithKey      | See notes 1, 3
+notMember           | not 'Math.Geometry.Grid.contains'
+null                | To find out if a grid has no /values/, extract the
+                    | map using 'toMap' and apply 'Data.Map.null' to
+                    | the result. To find out if a grid has no /tiles/,
+                    | use 'Math.Geometry.Grid.null'.
+partition           | See notes 1, 2
+partitionWithKey    | See notes 1, 2
 showTree            | See note 1
 showTreeWith        | See note 1
+singleton           | 'lazyGridMap' g [v]
+size                | To find out the number of /values/ in a grid,
+                    | extract the values using 'toList' and apply
+                    | 'length' to the result. To find out the
+                    | number of /tiles/, 'Math.Geometry.Grid.tileCount'.
+                    | To find out the dimensions of the grid, use
+                    | 'Math.Geometry.Grid.size'.
+split               | See notes 1, 2, 3
+splitLookup         | See notes 1, 2, 3
+toAscList           | See notes 1, 3
+toDescList          | See notes 1, 3
+toList              | See note 1
+traverseWithKey     | See notes 1, 2
+union               | See notes 1, 2
+unions              | See notes 1, 2
+unionsWith          | See notes 1, 2
+unionWithKey        | See notes 1, 2
+unionWith           | See notes 1, 2
+updateAt            | See notes 1, 3
+updateLookupWithKey | See note 1
+updateMax           | See notes 1, 3
+updateMaxWithKey    | See notes 1, 3
+updateMin           | See notes 1, 3
+updateMinWithKey    | See notes 1, 3
+update              | See note 1
+updateWithKey       | See note 1
 valid               | See note 1
 @
 
@@ -240,6 +440,10 @@
 maps. Comparisons such as /east of/ or /south of/ may be more useful.
 However, you can extract the map using @'toMap'@ and apply the function
 from @Data.Map@ to the result.
+
+4. It's not obvious what the behaviour should be if the two maps have
+different underlying grids. Different users may want different
+behaviour.
 -}
 
 
diff --git a/src/Math/Geometry/GridMap/Lazy.hs b/src/Math/Geometry/GridMap/Lazy.hs
--- a/src/Math/Geometry/GridMap/Lazy.hs
+++ b/src/Math/Geometry/GridMap/Lazy.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
--- Module      :  Math.Geometry.GridMap
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Module      :  Math.Geometry.GridMap.Lazy
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
@@ -19,7 +19,8 @@
 module Math.Geometry.GridMap.Lazy
   (
     LGridMap,
-    lazyGridMap
+    lazyGridMap,
+    empty
   ) where
 
 import Prelude hiding (lookup, map, foldr, foldl, foldr1, foldl1, null)
@@ -38,13 +39,16 @@
   LGridMap { lgmGrid :: g, lgmMap :: M.Map (G.Index g) v }
     deriving Generic
 
--- | Construct a grid map which is strict in the keys (tile positions), but
---   lazy in the values.
+-- | Construct a grid map which is strict in the keys (tile positions),
+--   but lazy in the values.
 lazyGridMap :: (Ord (G.Index g), G.Grid g) => g -> [v] -> LGridMap g v
 lazyGridMap g vs = LGridMap g (M.fromList kvs)
   where kvs = zip ks vs
         ks = G.indices g
 
+empty :: G.Grid g => g -> LGridMap g v
+empty g = LGridMap g M.empty
+
 instance (G.Grid g, Ord (G.Index g)) => Functor (LGridMap g) where
   fmap f gm = lazyGridMap (lgmGrid gm) (P.map f vs)
     where vs = M.elems (lgmMap gm)
@@ -83,10 +87,21 @@
   toMap = lgmMap
   toGrid = lgmGrid
   lookup k = M.lookup k . toMap
+  insertWithKey f k v gm = if gm `G.contains` k
+                   then gm { lgmMap = M.insertWithKey f k v $ lgmMap gm }
+                   else gm 
+  delete k gm = if gm `G.contains` k
+                   then gm { lgmMap = M.delete k $ lgmMap gm }
+                   else gm 
   adjustWithKey f k gm = gm { lgmMap = M.adjustWithKey f k (lgmMap gm)}
+  alter f k gm = if gm `G.contains` k
+                   then gm { lgmMap = M.alter f k $ lgmMap gm }
+                   else gm
   findWithDefault v k = fromMaybe v . lookup k
   map f (LGridMap g m) = LGridMap g (M.map f m)
   mapWithKey f (LGridMap g m) = LGridMap g (M.mapWithKey f m)
+  filter f (LGridMap g m) = LGridMap g (M.filter f m)
+  filterWithKey f (LGridMap g m) = LGridMap g (M.filterWithKey f m)
 
 instance (Eq g, Eq (G.Index g), Eq v) => Eq (LGridMap g v) where
   (==) (LGridMap g1 gm1) (LGridMap g2 gm2) = g1 == g2 && gm1 == gm2
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.Grid.Main
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
@@ -17,17 +17,19 @@
 import Math.Geometry.Grid.HexagonalQC ( test )
 import Math.Geometry.Grid.Hexagonal2QC ( test )
 import Math.Geometry.Grid.OctagonalQC ( test )
+import Math.Geometry.GridMap.LazyQC (test)
 
-import Test.Framework as TF ( defaultMain, Test )
+import Test.Framework ( defaultMain, Test )
 
-tests :: [TF.Test]
+tests :: [Test]
 tests = 
   [ 
     Math.Geometry.Grid.TriangularQC.test,
     Math.Geometry.Grid.SquareQC.test,
     Math.Geometry.Grid.HexagonalQC.test,
     Math.Geometry.Grid.Hexagonal2QC.test,
-    Math.Geometry.Grid.OctagonalQC.test
+    Math.Geometry.Grid.OctagonalQC.test,
+    Math.Geometry.GridMap.LazyQC.test
   ]
 
 main :: IO ()
diff --git a/test/Math/Geometry/Grid/Hexagonal2QC.hs b/test/Math/Geometry/Grid/Hexagonal2QC.hs
--- a/test/Math/Geometry/Grid/Hexagonal2QC.hs
+++ b/test/Math/Geometry/Grid/Hexagonal2QC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.Grid.Hexagonal2QC
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
@@ -24,7 +24,7 @@
 import Math.Geometry.GridQC
 
 import Prelude hiding (null)
-import Test.Framework as TF (Test, testGroup)
+import Test.Framework (Test, testGroup)
 import Test.QuickCheck 
   (Gen, Arbitrary, arbitrary, sized, elements, choose, Property, vectorOf)
 
diff --git a/test/Math/Geometry/Grid/HexagonalQC.hs b/test/Math/Geometry/Grid/HexagonalQC.hs
--- a/test/Math/Geometry/Grid/HexagonalQC.hs
+++ b/test/Math/Geometry/Grid/HexagonalQC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.Grid.RectangularQC
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
@@ -24,7 +24,7 @@
 import Math.Geometry.GridQC
 
 import Prelude hiding (null)
-import Test.Framework as TF (Test, testGroup)
+import Test.Framework (Test, testGroup)
 import Test.QuickCheck 
   (Gen, Arbitrary, arbitrary, sized, elements, choose, Property, vectorOf)
 
diff --git a/test/Math/Geometry/Grid/OctagonalQC.hs b/test/Math/Geometry/Grid/OctagonalQC.hs
--- a/test/Math/Geometry/Grid/OctagonalQC.hs
+++ b/test/Math/Geometry/Grid/OctagonalQC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.Grid.OctagonalQC
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
@@ -24,7 +24,7 @@
 import Math.Geometry.GridQC
 
 import Prelude hiding (null)
-import Test.Framework as TF (Test, testGroup)
+import Test.Framework (Test, testGroup)
 import Test.QuickCheck 
   (Gen, Arbitrary, arbitrary, sized, choose, elements, Property, vectorOf)
 
diff --git a/test/Math/Geometry/Grid/SquareQC.hs b/test/Math/Geometry/Grid/SquareQC.hs
--- a/test/Math/Geometry/Grid/SquareQC.hs
+++ b/test/Math/Geometry/Grid/SquareQC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.Grid.SquareQC
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
@@ -24,7 +24,7 @@
 import Math.Geometry.GridQC
 
 import Prelude hiding (null)
-import Test.Framework as TF (Test, testGroup)
+import Test.Framework (Test, testGroup)
 import Test.QuickCheck 
   (Gen, Arbitrary, arbitrary, sized, choose, elements,  Property, vectorOf)
 
diff --git a/test/Math/Geometry/Grid/TriangularQC.hs b/test/Math/Geometry/Grid/TriangularQC.hs
--- a/test/Math/Geometry/Grid/TriangularQC.hs
+++ b/test/Math/Geometry/Grid/TriangularQC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.Grid.TriangularQC
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
@@ -24,7 +24,7 @@
 import Math.Geometry.GridQC
 
 import Prelude hiding (null)
-import Test.Framework as TF (Test, testGroup)
+import Test.Framework (Test, testGroup)
 import Test.QuickCheck
   (Gen, Arbitrary, arbitrary, sized, choose, elements, Property,
     vectorOf, suchThat)
diff --git a/test/Math/Geometry/GridQC.hs b/test/Math/Geometry/GridQC.hs
--- a/test/Math/Geometry/GridQC.hs
+++ b/test/Math/Geometry/GridQC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Math.Geometry.Grid.GridQC
--- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- Copyright   :  (c) Amy de Buitléir 2012-2015
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
@@ -22,7 +22,7 @@
 import qualified Prelude as P (null)
 import Data.List (delete, nub, sort)
 import Data.Maybe (isJust, fromJust)
-import Test.Framework as TF (Test)
+import Test.Framework (Test)
 import Test.Framework.Providers.QuickCheck2 (testProperty)
 import Test.QuickCheck 
   ((==>), Gen, Arbitrary, arbitrary, choose, Property, property,
