diff --git a/.travis.yml b/.travis.yml
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,1 +1,8 @@
 language: haskell
+notifications:
+  irc:
+    channels:
+      - "irc.freenode.org#haskell-lens"
+    skip_join: true
+    template:
+      - "\x0313graphs\x03/\x0306%{branch}\x03 \x0314%{commit}\x03 %{build_url} %{message}"
diff --git a/Data/Graph/AdjacencyList.hs b/Data/Graph/AdjacencyList.hs
deleted file mode 100644
--- a/Data/Graph/AdjacencyList.hs
+++ /dev/null
@@ -1,55 +0,0 @@
-{-# LANGUAGE TypeFamilies, FlexibleContexts #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Data.Graph.Adjacency.List
--- Copyright   :  (C) 2011 Edward Kmett
--- License     :  BSD-style (see the file LICENSE)
---
--- Maintainer  :  Edward Kmett <ekmett@gmail.com>
--- Stability   :  experimental
--- Portability :  type families
---
-----------------------------------------------------------------------------
-
-module Data.Graph.AdjacencyList
-  ( AdjacencyList(..)
-  , ask
-  ) where
-
-import Control.Applicative
-import Data.Ix
-import Data.Array
-import Data.Graph.PropertyMap
-import Data.Graph.Class
-import Data.Graph.Class.AdjacencyList
-
-newtype AdjacencyList i a = AdjacencyList { runAdjacencyList :: Array i [i] -> a }  
-
-ask :: AdjacencyList i (Array i [i])
-ask = AdjacencyList id
-
-instance Functor (AdjacencyList i) where
-  fmap f (AdjacencyList g) = AdjacencyList (f . g)
-  b <$ _ = pure b
-
-instance Applicative (AdjacencyList i) where
-  pure = AdjacencyList . const
-  AdjacencyList f <*> AdjacencyList a = AdjacencyList $ \t -> f t (a t)
-
-instance Monad (AdjacencyList i) where
-  return = AdjacencyList . const
-  AdjacencyList f >>= k = AdjacencyList $ \t -> runAdjacencyList (k (f t)) t
-
-instance Ord i => Graph (AdjacencyList i) where
-  type Vertex (AdjacencyList i) = i
-  type Edge (AdjacencyList i) = (i, i)
-  vertexMap = pure . propertyMap
-  edgeMap = pure . propertyMap
-
-instance Ix i => AdjacencyListGraph (AdjacencyList i) where
-  adjacentVertices v = AdjacencyList $ \g -> if inRange (bounds g) v 
-                                     then g ! v 
-                                     else []
-  source (a, _) = pure a
-  target (_, b) = pure b
-  outEdges = defaultOutEdges
diff --git a/Data/Graph/AdjacencyMatrix.hs b/Data/Graph/AdjacencyMatrix.hs
deleted file mode 100644
--- a/Data/Graph/AdjacencyMatrix.hs
+++ /dev/null
@@ -1,56 +0,0 @@
-{-# LANGUAGE TypeFamilies, FlexibleContexts #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Data.Graph.Adjacency.Matrix
--- Copyright   :  (C) 2011 Edward Kmett
--- License     :  BSD-style (see the file LICENSE)
---
--- Maintainer  :  Edward Kmett <ekmett@gmail.com>
--- Stability   :  experimental
--- Portability :  type families
---
-----------------------------------------------------------------------------
-
-module Data.Graph.AdjacencyMatrix
-  ( AdjacencyMatrix(..)
-  , ask
-  ) where
-
-import Control.Applicative
-import Data.Ix
-import Data.Array.IArray
-import Data.Graph.PropertyMap
-import Data.Graph.Class
-import Data.Graph.Class.AdjacencyMatrix
-
-newtype AdjacencyMatrix arr i a = AdjacencyMatrix { runAdjacencyMatrix :: arr (i,i) Bool -> a } 
-
-ask :: AdjacencyMatrix arr i (arr (i, i) Bool)
-ask = AdjacencyMatrix id
-
-instance Functor (AdjacencyMatrix arr i) where
-  fmap f (AdjacencyMatrix g) = AdjacencyMatrix (f . g)
-  b <$ _ = pure b
-
-instance Applicative (AdjacencyMatrix arr i) where
-  pure = AdjacencyMatrix . const
-  AdjacencyMatrix f <*> AdjacencyMatrix a = AdjacencyMatrix $ \t -> f t (a t)
-
-instance Monad (AdjacencyMatrix arr i) where
-  return = AdjacencyMatrix . const
-  AdjacencyMatrix f >>= k = AdjacencyMatrix $ \t -> runAdjacencyMatrix (k (f t)) t
-
-instance Ord i => Graph (AdjacencyMatrix arr i) where
-  type Vertex (AdjacencyMatrix arr i) = i
-  type Edge (AdjacencyMatrix arr i) = (i, i) 
-  vertexMap = pure . propertyMap
-  edgeMap = pure . propertyMap
-
-instance (IArray arr Bool, Ix i) => AdjacencyMatrixGraph (AdjacencyMatrix arr i) where
-  edge i j = AdjacencyMatrix $ \a ->
-    if inRange (bounds a) ix && (a ! ix) 
-    then Just ix
-    else Nothing
-    where ix = (i, j)
-
-
diff --git a/Data/Graph/Algorithm/BreadthFirstSearch.hs b/Data/Graph/Algorithm/BreadthFirstSearch.hs
deleted file mode 100644
--- a/Data/Graph/Algorithm/BreadthFirstSearch.hs
+++ /dev/null
@@ -1,118 +0,0 @@
-{-# LANGUAGE TypeFamilies #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Data.Graph.Algorithm.BreadthFirstSearch
--- Copyright   :  (C) 2011 Edward Kmett
--- License     :  BSD-style (see the file LICENSE)
---
--- Maintainer  :  Edward Kmett <ekmett@gmail.com>
--- Stability   :  experimental
--- Portability :  type families
---
--- Breadth-first search
-----------------------------------------------------------------------------
-
-module Data.Graph.Algorithm.BreadthFirstSearch
-  ( bfs, Bfs(..)
-  ) where
-
-import Control.Applicative
-import Control.Monad
-import Control.Monad.Trans.Class
-import Control.Monad.Trans.State.Strict
-import Data.Foldable
-import Data.Monoid
-import Data.Sequence
-
-import Data.Graph.Class
-import Data.Graph.Class.AdjacencyList
-import Data.Graph.PropertyMap
-import Data.Graph.Internal.Color
-
--- | Breadth first search visitor 
-data Bfs g m = Bfs 
-  { enterVertex :: Vertex g -> g m -- called the first time a vertex is discovered
-  , grayTarget  :: Edge g   -> g m -- called when we encounter a back edge to a vertex we're still processing
-  , exitVertex  :: Vertex g -> g m -- called once we have processed all descendants of a vertex
-  , blackTarget :: Edge g   -> g m -- called when we encounter a cross edge to a vertex we've already finished
-  } 
-
-instance Graph g => Functor (Bfs g) where
-  fmap f (Bfs a b c d) = Bfs 
-    (liftM f . a)
-    (liftM f . b)
-    (liftM f . c)
-    (liftM f . d)
-
-instance Graph g => Applicative (Bfs g) where
-  pure a = Bfs 
-    (const (return a))
-    (const (return a))
-    (const (return a))
-    (const (return a))
-
-  m <*> n = Bfs
-    (\v -> enterVertex m v `ap` enterVertex n v)
-    (\e -> grayTarget m e `ap`  grayTarget n e)
-    (\v -> exitVertex m v `ap`  exitVertex n v)
-    (\e -> blackTarget m e `ap` blackTarget n e)
-
-instance Graph g => Monad (Bfs g) where
-  return = pure
-  m >>= f = Bfs
-    (\v -> enterVertex m v >>= ($ v) . enterVertex . f)
-    (\e -> grayTarget m e >>= ($ e) . grayTarget . f)
-    (\v -> exitVertex m v >>= ($ v) . exitVertex . f)
-    (\e -> blackTarget m e >>= ($ e) . blackTarget . f)
-
-instance (Graph g, Monoid m) => Monoid (Bfs g m) where
-  mempty = return mempty
-  mappend = liftM2 mappend
-
-getS :: Monad g => k -> StateT (Seq v, PropertyMap g k Color) g Color
-getS k = do
-  m <- gets snd 
-  lift (getP m k)
-
-putS :: Monad g => k -> Color -> StateT (Seq v, PropertyMap g k Color) g ()
-putS k v = do
-  m <- gets snd 
-  m' <- lift $ putP m k v
-  modify $ \(q,_) -> (q, m')
-
-enqueue :: Graph g 
-        => Bfs g m 
-        -> Vertex g 
-        -> StateT (Seq (Vertex g), PropertyMap g (Vertex g) Color) g m
-enqueue vis v = do
-  m <- gets snd
-  m' <- lift $ putP m v Grey
-  modify $ \(q,_) -> (q |> v, m')
-  lift $ enterVertex vis v
-
-dequeue :: Monad g => StateT (Seq v, s) g r -> (v -> StateT (Seq v, s) g r) -> StateT (Seq v, s) g r
-dequeue ke ks = do
-  (q, m) <- get
-  case viewl q of
-    EmptyL -> ke
-    (a :< q') -> put (q', m) >> ks a
-
-bfs :: (AdjacencyListGraph g, Monoid m) => Bfs g m -> Vertex g -> g m
-bfs vis v0 = do
-  m <- vertexMap White 
-  evalStateT (enqueue vis v0 >>= pump) (mempty, m) 
-  where
-  pump lhs = dequeue (return lhs) $ \ v -> do
-    adjs <- lift $ outEdges v
-    children <- foldrM 
-      (\e m -> do
-        v' <- target e
-        color <- getS v'
-        liftM (`mappend` m) $ case color of
-          White -> enqueue vis v' 
-          Grey -> lift $ grayTarget vis e
-          Black -> lift $ blackTarget vis e
-      ) mempty adjs
-    putS v Black
-    rhs <- lift $ exitVertex vis v 
-    pump $ lhs `mappend` children `mappend` rhs
diff --git a/Data/Graph/Algorithm/DepthFirstSearch.hs b/Data/Graph/Algorithm/DepthFirstSearch.hs
deleted file mode 100644
--- a/Data/Graph/Algorithm/DepthFirstSearch.hs
+++ /dev/null
@@ -1,103 +0,0 @@
-{-# LANGUAGE TypeFamilies #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Data.Graph.Algorithm.DepthFirstSearch
--- Copyright   :  (C) 2011 Edward Kmett
--- License     :  BSD-style (see the file LICENSE)
---
--- Maintainer  :  Edward Kmett <ekmett@gmail.com>
--- Stability   :  experimental
--- Portability :  type families
---
--- Depth-first search
-----------------------------------------------------------------------------
-
-module Data.Graph.Algorithm.DepthFirstSearch
-  ( dfs, Dfs(..)
-  ) where
-
-import Control.Applicative
-import Control.Monad
-import Control.Monad.Trans.Class
-import Control.Monad.Trans.State.Strict
-import Data.Foldable
-import Data.Monoid
-
-import Data.Graph.Class
-import Data.Graph.Class.AdjacencyList
-import Data.Graph.PropertyMap
-import Data.Graph.Internal.Color
-
-data Dfs g m = Dfs 
-  { enterVertex :: Vertex g -> g m -- called the first time a vertex is discovered
-  , grayTarget  :: Edge g   -> g m -- called when we encounter a back edge to a vertex we're still processing
-  , exitVertex  :: Vertex g -> g m -- called once we have processed all descendants of a vertex
-  , blackTarget :: Edge g   -> g m -- called when we encounter a cross edge to a vertex we've already finished
-  }
-
-instance Graph g => Functor (Dfs g) where
-  fmap f (Dfs a b c d) = Dfs 
-    (liftM f . a)
-    (liftM f . b)
-    (liftM f . c)
-    (liftM f . d)
-
-instance Graph g => Applicative (Dfs g) where
-  pure a = Dfs 
-    (const (return a))
-    (const (return a))
-    (const (return a))
-    (const (return a))
-
-  m <*> n = Dfs
-    (\v -> enterVertex m v `ap` enterVertex n v)
-    (\e -> grayTarget m e `ap`  grayTarget n e)
-    (\v -> exitVertex m v `ap`  exitVertex n v)
-    (\e -> blackTarget m e `ap` blackTarget n e)
-
-instance Graph g => Monad (Dfs g) where
-  return = pure
-  m >>= f = Dfs
-    (\v -> enterVertex m v >>= ($ v) . enterVertex . f)
-    (\e -> grayTarget m e >>= ($ e) . grayTarget . f)
-    (\v -> exitVertex m v >>= ($ v) . exitVertex . f)
-    (\e -> blackTarget m e >>= ($ e) . blackTarget . f)
-
-instance (Graph g, Monoid m) => Monoid (Dfs g m) where
-  mempty = return mempty
-  mappend = liftM2 mappend
-
-getS :: Monad g => k -> StateT (PropertyMap g k v) g v
-getS k = do
-  m <- get 
-  lift (getP m k)
-
-putS :: Monad g => k -> v -> StateT (PropertyMap g k v) g ()
-putS k v = do
-  m <- get 
-  m' <- lift $ putP m k v
-  put m'
-
--- TODO: CPS transform?
-dfs :: (AdjacencyListGraph g, Monoid m) => Dfs g m -> Vertex g -> g m
-dfs vis v0 = do
-  m <- vertexMap White 
-  evalStateT (go v0) m where
-  go v = do
-    putS v Grey
-    lhs <- lift $ enterVertex vis v
-    adjs <- lift $ outEdges v 
-    result <- foldrM 
-      (\e m -> do 
-        v' <- target e
-        color <- getS v'
-        liftM (`mappend` m) $ case color of
-          White -> go v'
-          Grey  -> lift $ grayTarget vis e
-          Black -> lift $ blackTarget vis e
-      ) 
-      mempty 
-      adjs
-    putS v Black
-    rhs <- lift $ exitVertex vis v
-    return $ lhs `mappend` result `mappend` rhs
diff --git a/Data/Graph/Class.hs b/Data/Graph/Class.hs
deleted file mode 100644
--- a/Data/Graph/Class.hs
+++ /dev/null
@@ -1,127 +0,0 @@
-{-# LANGUAGE TypeFamilies, FlexibleContexts #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Data.Graph.Class
--- Copyright   :  (C) 2011 Edward Kmett
--- License     :  BSD-style (see the file LICENSE)
---
--- Maintainer  :  Edward Kmett <ekmett@gmail.com>
--- Stability   :  experimental
--- Portability :  type families
---
-----------------------------------------------------------------------------
-
-module Data.Graph.Class 
-  ( Graph(..)
-  , VertexMap
-  , EdgeMap
-  , liftVertexMap
-  , liftEdgeMap
-  ) where
-
-import Control.Monad
-import qualified Control.Monad.Trans.State.Strict as Strict
-import qualified Control.Monad.Trans.State.Lazy as Lazy
-import qualified Control.Monad.Trans.Writer.Strict as Strict
-import qualified Control.Monad.Trans.Writer.Lazy as Lazy
-import qualified Control.Monad.Trans.RWS.Strict as Strict
-import qualified Control.Monad.Trans.RWS.Lazy as Lazy
-import Control.Monad.Trans.Identity
-import Control.Monad.Trans.Maybe
-import Control.Monad.Trans.Error
-import Control.Monad.Trans.Reader 
-import Control.Monad.Trans.Class
-import Data.Functor.Identity
-import Data.Monoid
-import Data.Graph.PropertyMap
-import Data.Void
-
-type VertexMap g = PropertyMap g (Vertex g)
-type EdgeMap g = PropertyMap g (Edge g)
-
-class (Monad g, Eq (Vertex g), Eq (Edge g)) => Graph g where
-  type Vertex g :: *
-  type Edge g :: * 
-  vertexMap :: a -> g (VertexMap g a)
-  edgeMap   :: a -> g (EdgeMap g a)
-
-liftVertexMap :: (MonadTrans t, Graph (t g), Graph g, Vertex (t g) ~ Vertex g) 
-              => a -> t g (VertexMap (t g) a)
-liftVertexMap = lift . liftM liftPropertyMap . vertexMap
-{-# INLINE liftVertexMap #-}
-
-liftEdgeMap :: (MonadTrans t, Graph (t g), Graph g, Edge (t g) ~ Edge g) 
-            => a -> t g (EdgeMap (t g) a)
-liftEdgeMap = lift . liftM liftPropertyMap . edgeMap
-{-# INLINE liftEdgeMap #-}
-
-instance Graph g => Graph (Strict.StateT s g) where
-  type Vertex (Strict.StateT s g) = Vertex g
-  type Edge (Strict.StateT s g) = Edge g
-  vertexMap = liftVertexMap
-  edgeMap = liftEdgeMap
-
-instance Graph g => Graph (Lazy.StateT s g) where
-  type Vertex (Lazy.StateT s g) = Vertex g
-  type Edge (Lazy.StateT s g) = Edge g
-  vertexMap = liftVertexMap
-  edgeMap = liftEdgeMap
-
-instance (Graph g, Monoid m) => Graph (Strict.WriterT m g) where
-  type Vertex (Strict.WriterT m g) = Vertex g
-  type Edge (Strict.WriterT m g) = Edge g
-  vertexMap = liftVertexMap
-  edgeMap = liftEdgeMap
-
-instance (Graph g, Monoid m) => Graph (Lazy.WriterT m g) where
-  type Vertex (Lazy.WriterT m g) = Vertex g
-  type Edge (Lazy.WriterT m g) = Edge g
-  vertexMap = liftVertexMap
-  edgeMap = liftEdgeMap
-
-instance Graph g => Graph (ReaderT m g) where
-  type Vertex (ReaderT m g) = Vertex g 
-  type Edge (ReaderT m g) = Edge g
-  vertexMap = liftVertexMap
-  edgeMap = liftEdgeMap
-
-instance Graph g => Graph (IdentityT g) where
-  type Vertex (IdentityT g) = Vertex g
-  type Edge (IdentityT g) = Edge g
-  vertexMap = liftVertexMap
-  edgeMap = liftEdgeMap
-
-instance Graph g => Graph (MaybeT g) where
-  type Vertex (MaybeT g) = Vertex g
-  type Edge (MaybeT g) = Edge g
-  vertexMap = liftVertexMap
-  edgeMap = liftEdgeMap
-
-instance (Graph g, Error e) => Graph (ErrorT e g) where
-  type Vertex (ErrorT e g) = Vertex g
-  type Edge (ErrorT e g) = Edge g
-  vertexMap = liftVertexMap
-  edgeMap = liftEdgeMap
-
-instance (Graph g, Monoid w) => Graph (Lazy.RWST r w s g) where
-  type Vertex (Lazy.RWST r w s g) = Vertex g
-  type Edge (Lazy.RWST r w s g) = Edge g
-  vertexMap = liftVertexMap
-  edgeMap = liftEdgeMap
-
-instance (Graph g, Monoid w) => Graph (Strict.RWST r w s g) where
-  type Vertex (Strict.RWST r w s g) = Vertex g
-  type Edge (Strict.RWST r w s g) = Edge g
-  vertexMap = liftVertexMap
-  edgeMap = liftEdgeMap
-
-voidMap :: PropertyMap Identity Void a
-voidMap = PropertyMap (Identity . absurd) $ \_ _ -> Identity voidMap
-
--- | The empty graph
-instance Graph Identity where
-  type Vertex Identity = Void
-  type Edge Identity = Void
-  vertexMap _ = Identity voidMap 
-  edgeMap   _ = Identity voidMap
-
diff --git a/Data/Graph/Class/AdjacencyList.hs b/Data/Graph/Class/AdjacencyList.hs
deleted file mode 100644
--- a/Data/Graph/Class/AdjacencyList.hs
+++ /dev/null
@@ -1,129 +0,0 @@
-{-# LANGUAGE TypeFamilies, FlexibleInstances #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Data.Graph.Class.AdjacencyList
--- Copyright   :  (C) 2011 Edward Kmett
--- License     :  BSD-style (see the file LICENSE)
---
--- Maintainer  :  Edward Kmett <ekmett@gmail.com>
--- Stability   :  experimental
--- Portability :  type families
---
-----------------------------------------------------------------------------
-
-module Data.Graph.Class.AdjacencyList
-  ( AdjacencyListGraph(..)
-  , defaultOutEdges
-  , module Data.Graph.Class
-  ) where
-
-import Control.Monad
-import Control.Monad.Trans.Class
-import qualified Control.Monad.Trans.State.Strict as Strict
-import qualified Control.Monad.Trans.State.Lazy as Lazy
-import qualified Control.Monad.Trans.Writer.Strict as Strict
-import qualified Control.Monad.Trans.Writer.Lazy as Lazy
-import qualified Control.Monad.Trans.RWS.Strict as Strict
-import qualified Control.Monad.Trans.RWS.Lazy as Lazy
-import Control.Monad.Trans.Identity
-import Control.Monad.Trans.Maybe
-import Control.Monad.Trans.Error
-import Control.Monad.Trans.Reader
-import Data.Functor.Identity
-import Data.Monoid
-import Data.Graph.Class
-
-defaultOutEdges :: AdjacencyListGraph g => Vertex g -> g [(Vertex g, Vertex g)]
-defaultOutEdges v = liftM (map ((,) v)) (adjacentVertices v)
-
--- | Minimal definition: 'source', 'target', and either 'adjacentVertices' with @'outEdges' = 'defaultOutEdges'@ or 'outEdges'
-class Graph g => AdjacencyListGraph g where
-  -- /O(1)/
-  source :: Edge g -> g (Vertex g)
-  -- /O(1)/
-  target :: Edge g -> g (Vertex g)
-  -- /O(e)/ in the number of out edges
-  outEdges :: Vertex g -> g [Edge g]
-
-  -- /O(e)/
-  outDegree :: Vertex g -> g Int
-  outDegree v = liftM length (outEdges v)
-
-  adjacentVertices :: Vertex g -> g [Vertex g]
-  adjacentVertices = outEdges >=> mapM target
-
-instance AdjacencyListGraph g => AdjacencyListGraph (Strict.StateT s g) where
-  adjacentVertices = lift . adjacentVertices
-  source = lift . source
-  target = lift . target
-  outEdges = lift . outEdges
-  outDegree = lift . outDegree
-
-instance AdjacencyListGraph g => AdjacencyListGraph (Lazy.StateT s g) where
-  adjacentVertices = lift . adjacentVertices
-  source = lift . source
-  target = lift . target
-  outEdges = lift . outEdges
-  outDegree = lift . outDegree
-
-instance (AdjacencyListGraph g, Monoid m) => AdjacencyListGraph (Strict.WriterT m g) where
-  adjacentVertices = lift . adjacentVertices
-  source = lift . source
-  target = lift . target
-  outEdges = lift . outEdges
-  outDegree = lift . outDegree
-
-instance (AdjacencyListGraph g, Monoid m) => AdjacencyListGraph (Lazy.WriterT m g) where
-  adjacentVertices = lift . adjacentVertices
-  source = lift . source
-  target = lift . target
-  outEdges = lift . outEdges
-  outDegree = lift . outDegree
-
-instance (AdjacencyListGraph g, Monoid m) => AdjacencyListGraph (Strict.RWST r m s g) where
-  adjacentVertices = lift . adjacentVertices
-  source = lift . source
-  target = lift . target
-  outEdges = lift . outEdges
-  outDegree = lift . outDegree
-
-instance (AdjacencyListGraph g, Monoid m) => AdjacencyListGraph (Lazy.RWST r m s g) where
-  adjacentVertices = lift . adjacentVertices
-  source = lift . source
-  target = lift . target
-  outEdges = lift . outEdges
-  outDegree = lift . outDegree
-
-instance AdjacencyListGraph g => AdjacencyListGraph (ReaderT e g) where
-  adjacentVertices = lift . adjacentVertices
-  source = lift . source
-  target = lift . target
-  outEdges = lift . outEdges
-  outDegree = lift . outDegree
-
-instance (AdjacencyListGraph g, Error e) => AdjacencyListGraph (ErrorT e g) where
-  adjacentVertices = lift . adjacentVertices
-  source = lift . source
-  target = lift . target
-  outEdges = lift . outEdges
-  outDegree = lift . outDegree
-
-instance AdjacencyListGraph g => AdjacencyListGraph (MaybeT g) where
-  adjacentVertices = lift . adjacentVertices
-  source = lift . source
-  target = lift . target
-  outEdges = lift . outEdges
-  outDegree = lift . outDegree
-
-instance AdjacencyListGraph g => AdjacencyListGraph (IdentityT g) where
-  adjacentVertices = lift . adjacentVertices
-  source = lift . source
-  target = lift . target
-  outEdges = lift . outEdges
-  outDegree = lift . outDegree
-
-instance AdjacencyListGraph Identity where
-  source = Identity
-  target = Identity
-  outEdges _ = Identity []
-  outDegree _ = Identity 0
diff --git a/Data/Graph/Class/AdjacencyMatrix.hs b/Data/Graph/Class/AdjacencyMatrix.hs
deleted file mode 100644
--- a/Data/Graph/Class/AdjacencyMatrix.hs
+++ /dev/null
@@ -1,68 +0,0 @@
-{-# LANGUAGE TypeFamilies, FlexibleInstances #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Data.Graph.Class.AdjacencyMatrix
--- Copyright   :  (C) 2011 Edward Kmett
--- License     :  BSD-style (see the file LICENSE)
---
--- Maintainer  :  Edward Kmett <ekmett@gmail.com>
--- Stability   :  experimental
--- Portability :  type families
---
-----------------------------------------------------------------------------
-
-module Data.Graph.Class.AdjacencyMatrix
-  ( AdjacencyMatrixGraph(..)
-  , module Data.Graph.Class
-  ) where
-
-import qualified Control.Monad.Trans.State.Strict as Strict
-import qualified Control.Monad.Trans.State.Lazy as Lazy
-import qualified Control.Monad.Trans.Writer.Strict as Strict
-import qualified Control.Monad.Trans.Writer.Lazy as Lazy
-import qualified Control.Monad.Trans.RWS.Strict as Strict
-import qualified Control.Monad.Trans.RWS.Lazy as Lazy
-import Control.Monad.Trans.Reader
-import Control.Monad.Trans.Maybe
-import Control.Monad.Trans.Identity
-import Control.Monad.Trans.Error
-import Control.Monad.Trans.Class
-import Data.Functor.Identity
-import Data.Monoid
-import Data.Graph.Class
-
-class Graph g => AdjacencyMatrixGraph g where
-  edge :: Vertex g -> Vertex g -> g (Maybe (Edge g))
-
-instance AdjacencyMatrixGraph g => AdjacencyMatrixGraph (Strict.StateT s g) where
-  edge a b = lift (edge a b)
-
-instance AdjacencyMatrixGraph g => AdjacencyMatrixGraph (Lazy.StateT s g) where
-  edge a b = lift (edge a b)
-
-instance (AdjacencyMatrixGraph g, Monoid m) => AdjacencyMatrixGraph (Strict.WriterT m g) where
-  edge a b = lift (edge a b)
-
-instance (AdjacencyMatrixGraph g, Monoid m) => AdjacencyMatrixGraph (Lazy.WriterT m g) where
-  edge a b = lift (edge a b)
-
-instance (AdjacencyMatrixGraph g, Monoid m) => AdjacencyMatrixGraph (Strict.RWST r m s g) where
-  edge a b = lift (edge a b)
-
-instance (AdjacencyMatrixGraph g, Monoid m) => AdjacencyMatrixGraph (Lazy.RWST r m s g) where
-  edge a b = lift (edge a b)
-
-instance AdjacencyMatrixGraph g => AdjacencyMatrixGraph (MaybeT g) where
-  edge a b = lift (edge a b)
-
-instance (AdjacencyMatrixGraph g, Error e) => AdjacencyMatrixGraph (ErrorT e g) where
-  edge a b = lift (edge a b)
-
-instance AdjacencyMatrixGraph g => AdjacencyMatrixGraph (IdentityT g) where
-  edge a b = lift (edge a b)
-
-instance AdjacencyMatrixGraph g => AdjacencyMatrixGraph (ReaderT e g) where
-  edge a b = lift (edge a b)
-
-instance AdjacencyMatrixGraph Identity where
-  edge _ _ = Identity Nothing
diff --git a/Data/Graph/Class/Bidirectional.hs b/Data/Graph/Class/Bidirectional.hs
deleted file mode 100644
--- a/Data/Graph/Class/Bidirectional.hs
+++ /dev/null
@@ -1,113 +0,0 @@
-{-# LANGUAGE TypeFamilies, FlexibleInstances #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Data.Graph.Class.Bidirectional
--- Copyright   :  (C) 2011 Edward Kmett
--- License     :  BSD-style (see the file LICENSE)
---
--- Maintainer  :  Edward Kmett <ekmett@gmail.com>
--- Stability   :  experimental
--- Portability :  type families
---
-----------------------------------------------------------------------------
-
-module Data.Graph.Class.Bidirectional 
-  ( BidirectionalGraph(..)
-  , module Data.Graph.Class.AdjacencyList
-  ) where
-
-import Control.Monad
-import Control.Monad.Trans.Class
-import qualified Control.Monad.Trans.State.Strict as Strict
-import qualified Control.Monad.Trans.State.Lazy as Lazy
-import qualified Control.Monad.Trans.Writer.Strict as Strict
-import qualified Control.Monad.Trans.Writer.Lazy as Lazy
-import qualified Control.Monad.Trans.RWS.Strict as Strict
-import qualified Control.Monad.Trans.RWS.Lazy as Lazy
-import Control.Monad.Trans.Reader
-import Control.Monad.Trans.Identity
-import Control.Monad.Trans.Maybe
-import Control.Monad.Trans.Error
-import Data.Functor.Identity
-import Data.Monoid
-import Data.Graph.Class.AdjacencyList
-
-class AdjacencyListGraph g => BidirectionalGraph g where
-  -- /O(e)/
-  inEdges :: Vertex g -> g [Edge g]
-  -- /O(e)/
-  inDegree :: Vertex g -> g Int
-  inDegree v = length `liftM` inEdges v
-  
-  incidentEdges :: Vertex g -> g [Edge g]
-  incidentEdges v = liftM2 (++) (inEdges v) (outEdges v)
-
-  degree :: Vertex g -> g Int
-  degree v = liftM2 (+) (inDegree v) (outDegree v)
-
-instance BidirectionalGraph g => BidirectionalGraph (Strict.StateT s g) where
-  inEdges  = lift . inEdges
-  inDegree = lift . inDegree
-  incidentEdges = lift . incidentEdges
-  degree = lift . degree
-
-instance BidirectionalGraph g => BidirectionalGraph (Lazy.StateT s g) where
-  inEdges  = lift . inEdges
-  inDegree = lift . inDegree
-  incidentEdges = lift . incidentEdges
-  degree = lift . degree
-
-instance (BidirectionalGraph g, Monoid m) => BidirectionalGraph (Strict.WriterT m g) where
-  inEdges  = lift . inEdges
-  inDegree = lift . inDegree
-  incidentEdges = lift . incidentEdges
-  degree = lift . degree
-
-instance (BidirectionalGraph g, Monoid m) => BidirectionalGraph (Lazy.WriterT m g) where
-  inEdges  = lift . inEdges
-  inDegree = lift . inDegree
-  incidentEdges = lift . incidentEdges
-  degree = lift . degree
-
-instance (BidirectionalGraph g, Monoid m) => BidirectionalGraph (Strict.RWST r m s g) where
-  inEdges  = lift . inEdges
-  inDegree = lift . inDegree
-  incidentEdges = lift . incidentEdges
-  degree = lift . degree
-
-instance (BidirectionalGraph g, Monoid m) => BidirectionalGraph (Lazy.RWST r m s g) where
-  inEdges  = lift . inEdges
-  inDegree = lift . inDegree
-  incidentEdges = lift . incidentEdges
-  degree = lift . degree
-
-instance BidirectionalGraph g => BidirectionalGraph (ReaderT e g) where
-  inEdges  = lift . inEdges
-  inDegree = lift . inDegree
-  incidentEdges = lift . incidentEdges
-  degree = lift . degree
-
-instance BidirectionalGraph g => BidirectionalGraph (IdentityT g) where
-  inEdges  = lift . inEdges
-  inDegree = lift . inDegree
-  incidentEdges = lift . incidentEdges
-  degree = lift . degree
-
-instance BidirectionalGraph g => BidirectionalGraph (MaybeT g) where
-  inEdges  = lift . inEdges
-  inDegree = lift . inDegree
-  incidentEdges = lift . incidentEdges
-  degree = lift . degree
-
-instance (BidirectionalGraph g, Error e) => BidirectionalGraph (ErrorT e g) where
-  inEdges  = lift . inEdges
-  inDegree = lift . inDegree
-  incidentEdges = lift . incidentEdges
-  degree = lift . degree
-
-instance BidirectionalGraph Identity where
-  inEdges _ = Identity []
-  inDegree _ = Identity 0
-  incidentEdges _ = Identity []
-  degree _  = Identity 0
-
diff --git a/Data/Graph/Class/EdgeEnumerable.hs b/Data/Graph/Class/EdgeEnumerable.hs
deleted file mode 100644
--- a/Data/Graph/Class/EdgeEnumerable.hs
+++ /dev/null
@@ -1,69 +0,0 @@
-{-# LANGUAGE TypeFamilies, FlexibleContexts #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Data.Graph.Class.EdgeEnumerable
--- Copyright   :  (C) 2011 Edward Kmett
--- License     :  BSD-style (see the file LICENSE)
---
--- Maintainer  :  Edward Kmett <ekmett@gmail.com>
--- Stability   :  experimental
--- Portability :  type families
---
-----------------------------------------------------------------------------
-
-module Data.Graph.Class.EdgeEnumerable
-  ( EdgeEnumerableGraph(..)
-  , module Data.Graph.Class
-  ) where
-
-import qualified Control.Monad.Trans.State.Strict as Strict
-import qualified Control.Monad.Trans.State.Lazy as Lazy
-import qualified Control.Monad.Trans.Writer.Strict as Strict
-import qualified Control.Monad.Trans.Writer.Lazy as Lazy
-import qualified Control.Monad.Trans.RWS.Strict as Strict
-import qualified Control.Monad.Trans.RWS.Lazy as Lazy
-import Control.Monad.Trans.Reader
-import Control.Monad.Trans.Identity
-import Control.Monad.Trans.Maybe
-import Control.Monad.Trans.Error
-import Control.Monad.Trans.Class
-import Data.Functor.Identity
-import Data.Monoid
-import Data.Graph.Class
-
-class Graph g => EdgeEnumerableGraph g where
-  -- | /O(e)/
-  edges :: g [Edge g]
-
-instance EdgeEnumerableGraph g => EdgeEnumerableGraph (Strict.StateT s g) where
-  edges = lift edges
-
-instance EdgeEnumerableGraph g => EdgeEnumerableGraph (Lazy.StateT s g) where
-  edges = lift edges
-
-instance (EdgeEnumerableGraph g, Monoid m) => EdgeEnumerableGraph (Strict.WriterT m g) where
-  edges = lift edges
-
-instance (EdgeEnumerableGraph g, Monoid m) => EdgeEnumerableGraph (Lazy.WriterT m g) where
-  edges = lift edges
-
-instance (EdgeEnumerableGraph g, Monoid m) => EdgeEnumerableGraph (Strict.RWST r m s g) where
-  edges = lift edges
-
-instance (EdgeEnumerableGraph g, Monoid m) => EdgeEnumerableGraph (Lazy.RWST r m s g) where
-  edges = lift edges
-
-instance EdgeEnumerableGraph g => EdgeEnumerableGraph (MaybeT g) where
-  edges = lift edges
-
-instance EdgeEnumerableGraph g => EdgeEnumerableGraph (IdentityT g) where
-  edges = lift edges
-
-instance (EdgeEnumerableGraph g, Error e) => EdgeEnumerableGraph (ErrorT e g) where
-  edges = lift edges
-
-instance EdgeEnumerableGraph g => EdgeEnumerableGraph (ReaderT e g) where
-  edges = lift edges
-
-instance EdgeEnumerableGraph Identity where
-  edges = Identity []
diff --git a/Data/Graph/Class/VertexEnumerable.hs b/Data/Graph/Class/VertexEnumerable.hs
deleted file mode 100644
--- a/Data/Graph/Class/VertexEnumerable.hs
+++ /dev/null
@@ -1,69 +0,0 @@
-{-# LANGUAGE TypeFamilies, FlexibleContexts #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Data.Graph.Class.VertexEnumerable
--- Copyright   :  (C) 2011 Edward Kmett
--- License     :  BSD-style (see the file LICENSE)
---
--- Maintainer  :  Edward Kmett <ekmett@gmail.com>
--- Stability   :  experimental
--- Portability :  type families
---
-----------------------------------------------------------------------------
-
-module Data.Graph.Class.VertexEnumerable
-  ( VertexEnumerableGraph(..)
-  , module Data.Graph.Class
-  ) where
-
-import qualified Control.Monad.Trans.State.Strict as Strict
-import qualified Control.Monad.Trans.State.Lazy as Lazy
-import qualified Control.Monad.Trans.Writer.Strict as Strict
-import qualified Control.Monad.Trans.Writer.Lazy as Lazy
-import qualified Control.Monad.Trans.RWS.Strict as Strict
-import qualified Control.Monad.Trans.RWS.Lazy as Lazy
-import Control.Monad.Trans.Identity
-import Control.Monad.Trans.Maybe
-import Control.Monad.Trans.Error
-import Control.Monad.Trans.Class
-import Control.Monad.Trans.Reader
-import Data.Monoid
-import Data.Graph.Class
-import Data.Functor.Identity
-
-class Graph g => VertexEnumerableGraph g where
-  -- | /O(v)/
-  vertices :: g [Vertex g]
-
-instance VertexEnumerableGraph g => VertexEnumerableGraph (Strict.StateT s g) where
-  vertices = lift vertices
-
-instance VertexEnumerableGraph g => VertexEnumerableGraph (Lazy.StateT s g) where
-  vertices = lift vertices
-
-instance (VertexEnumerableGraph g, Monoid m) => VertexEnumerableGraph (Strict.WriterT m g) where
-  vertices = lift vertices
-
-instance (VertexEnumerableGraph g, Monoid m) => VertexEnumerableGraph (Lazy.WriterT m g) where
-  vertices = lift vertices
-
-instance (VertexEnumerableGraph g, Monoid m) => VertexEnumerableGraph (Strict.RWST r m s g) where
-  vertices = lift vertices
-  
-instance (VertexEnumerableGraph g, Monoid m) => VertexEnumerableGraph (Lazy.RWST r m s g) where
-  vertices = lift vertices
-
-instance VertexEnumerableGraph g => VertexEnumerableGraph (MaybeT g) where
-  vertices = lift vertices
-
-instance VertexEnumerableGraph g => VertexEnumerableGraph (IdentityT g) where
-  vertices = lift vertices
-
-instance (VertexEnumerableGraph g, Error e) => VertexEnumerableGraph (ErrorT e g) where
-  vertices = lift vertices
-
-instance VertexEnumerableGraph g => VertexEnumerableGraph (ReaderT m g) where
-  vertices = lift vertices
-
-instance VertexEnumerableGraph Identity where
-  vertices = Identity []
diff --git a/Data/Graph/Dual.hs b/Data/Graph/Dual.hs
deleted file mode 100644
--- a/Data/Graph/Dual.hs
+++ /dev/null
@@ -1,73 +0,0 @@
-{-# LANGUAGE TypeFamilies, FlexibleContexts #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Data.Graph.Dual
--- Copyright   :  (C) 2011 Edward Kmett
--- License     :  BSD-style (see the file LICENSE)
---
--- Maintainer  :  Edward Kmett <ekmett@gmail.com>
--- Stability   :  experimental
--- Portability :  type families
---
-----------------------------------------------------------------------------
-
-module Data.Graph.Dual
-  ( Dual(..)
-  ) where
-
-import Control.Applicative
-import Control.Monad
-import Control.Monad.Trans.Class
-import Data.Graph.PropertyMap
-import Data.Graph.Class.AdjacencyList
-import Data.Graph.Class.AdjacencyMatrix
-import Data.Graph.Class.EdgeEnumerable
-import Data.Graph.Class.VertexEnumerable
-import Data.Graph.Class.Bidirectional
-
-newtype Dual g a = Dual { runDual :: g a }
-
-instance MonadTrans Dual where
-  lift = Dual
-
-instance Functor g => Functor (Dual g) where
-  fmap f (Dual g) = Dual $ fmap f g
-  b <$ Dual g = Dual $ b <$ g
-
-instance Applicative g => Applicative (Dual g) where
-  pure = Dual . pure
-  Dual f <*> Dual a = Dual (f <*> a)
-  Dual f <*  Dual a = Dual (f <*  a)
-  Dual f  *> Dual a = Dual (f  *> a)
-
-instance Monad g => Monad (Dual g) where
-  return = Dual . return
-  Dual g >>= k = Dual (g >>= runDual . k)
-  Dual g >> Dual h = Dual (g >> h)
-
-instance Graph g => Graph (Dual g) where
-  type Vertex (Dual g) = Vertex g
-  type Edge (Dual g) = Edge g
-  vertexMap = Dual . liftM liftPropertyMap . vertexMap
-  edgeMap   = Dual . liftM liftPropertyMap . edgeMap
-
-instance AdjacencyMatrixGraph g => AdjacencyMatrixGraph (Dual g) where
-  edge l r = Dual (edge r l)
-
-instance BidirectionalGraph g => AdjacencyListGraph (Dual g) where
-  source = Dual . target
-  target = Dual . source
-  outEdges = Dual . inEdges
-  outDegree = Dual . inDegree
-
-instance BidirectionalGraph g => BidirectionalGraph (Dual g) where
-  inEdges = Dual . outEdges
-  inDegree = Dual . inDegree
-  incidentEdges = Dual . incidentEdges
-  degree = Dual . degree
-
-instance EdgeEnumerableGraph g => EdgeEnumerableGraph (Dual g) where
-  edges = Dual edges 
-
-instance VertexEnumerableGraph g => VertexEnumerableGraph (Dual g) where
-  vertices = Dual vertices
diff --git a/Data/Graph/Internal/Color.hs b/Data/Graph/Internal/Color.hs
deleted file mode 100644
--- a/Data/Graph/Internal/Color.hs
+++ /dev/null
@@ -1,3 +0,0 @@
-module Data.Graph.Internal.Color where
-
-data Color = White | Grey | Black deriving (Eq,Ord,Show,Read)
diff --git a/Data/Graph/PropertyMap.hs b/Data/Graph/PropertyMap.hs
deleted file mode 100644
--- a/Data/Graph/PropertyMap.hs
+++ /dev/null
@@ -1,69 +0,0 @@
------------------------------------------------------------------------------
--- |
--- Module      :  Data.Graph.PropertyMap
--- Copyright   :  (C) 2011 Edward Kmett
--- License     :  BSD-style (see the file LICENSE)
---
--- Maintainer  :  Edward Kmett <ekmett@gmail.com>
--- Stability   :  experimental
--- Portability :  portable
---
--- Total transient monadic maps, used to track information about vertices
--- and edges in a graph
-----------------------------------------------------------------------------
-
-module Data.Graph.PropertyMap 
-  ( PropertyMap(..)
-  , modifyP
-  , intPropertyMap
-  , propertyMap
-  , liftPropertyMap
-  ) where
-
-import Control.Monad
-import Control.Monad.Trans.Class
-import qualified Data.IntMap as IntMap
-import qualified Data.Map as Map
-
-data PropertyMap m k v = PropertyMap
-  { getP :: k -> m v
-  , putP :: k -> v -> m (PropertyMap m k v)
-  }
-
-modifyP :: Monad m => PropertyMap m k v -> k -> (v -> v) -> m (PropertyMap m k v)
-modifyP m k f = do
-  a <- getP m k
-  putP m k (f a)
-
--- A pure IntMap-backed vertex map
-intPropertyMap :: Monad m => v -> PropertyMap m Int v
-intPropertyMap v0 = go v0 IntMap.empty where
-  go v m = PropertyMap 
-    { getP = \k -> return $ maybe v id (IntMap.lookup k m)
-    , putP = \k v' -> return $ go v (IntMap.insert k v' m)
-    }
-
--- A pure Map-backed vertex map
-propertyMap :: (Monad m, Ord k) => v -> PropertyMap m k v
-propertyMap v0 = go v0 Map.empty where
-  go v m = PropertyMap 
-    { getP = \k -> return $ maybe v id (Map.lookup k m)
-    , putP = \k v' -> return $ go v (Map.insert k v' m)
-    }
-
-liftPropertyMap :: (MonadTrans t, Monad m, Monad (t m)) => PropertyMap m k v -> PropertyMap (t m) k v
-liftPropertyMap (PropertyMap g p) = PropertyMap (lift . g) (\k v -> liftPropertyMap `liftM` lift (p k v))
-
-{-
--- An impure STArray-backed vertex map
-stAdjVertexMap :: (DenseAdjacencyMatrix g, MonadST s g) => a -> g (PropertyMap g (Vertex g) a)
-stAdjVertexMap v0 = do
-  range <- vertexRange 
-  arr <- newSTArray range v0
-  return $ go arr
-  where
-    go arr = r where r = VertexMap
-      { getP = readSTArray arr
-      , putP = \k v -> writeSTArray arr k v >> return r
-      } 
--}
diff --git a/graphs.cabal b/graphs.cabal
--- a/graphs.cabal
+++ b/graphs.cabal
@@ -1,6 +1,6 @@
 name:          graphs
 category:      Data Structures
-version:       0.4.0.3
+version:       0.4.1
 license:       BSD3
 cabal-version: >= 1.6
 license-file:  LICENSE
@@ -30,7 +30,7 @@
     array        >= 0.3     && < 0.5,
     transformers >= 0.2.2   && < 0.4,
     containers   >= 0.3     && < 0.6,
-    void         >= 0.5.5.1 && < 0.6
+    void         >= 0.5.5.1
 
   exposed-modules:
     Data.Graph.AdjacencyList
@@ -49,3 +49,4 @@
     Data.Graph.Internal.Color
 
   ghc-options: -Wall
+  hs-source-dirs: src
diff --git a/src/Data/Graph/AdjacencyList.hs b/src/Data/Graph/AdjacencyList.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Graph/AdjacencyList.hs
@@ -0,0 +1,55 @@
+{-# LANGUAGE TypeFamilies, FlexibleContexts #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Graph.Adjacency.List
+-- Copyright   :  (C) 2011 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  type families
+--
+----------------------------------------------------------------------------
+
+module Data.Graph.AdjacencyList
+  ( AdjacencyList(..)
+  , ask
+  ) where
+
+import Control.Applicative
+import Data.Ix
+import Data.Array
+import Data.Graph.PropertyMap
+import Data.Graph.Class
+import Data.Graph.Class.AdjacencyList
+
+newtype AdjacencyList i a = AdjacencyList { runAdjacencyList :: Array i [i] -> a }  
+
+ask :: AdjacencyList i (Array i [i])
+ask = AdjacencyList id
+
+instance Functor (AdjacencyList i) where
+  fmap f (AdjacencyList g) = AdjacencyList (f . g)
+  b <$ _ = pure b
+
+instance Applicative (AdjacencyList i) where
+  pure = AdjacencyList . const
+  AdjacencyList f <*> AdjacencyList a = AdjacencyList $ \t -> f t (a t)
+
+instance Monad (AdjacencyList i) where
+  return = AdjacencyList . const
+  AdjacencyList f >>= k = AdjacencyList $ \t -> runAdjacencyList (k (f t)) t
+
+instance Ord i => Graph (AdjacencyList i) where
+  type Vertex (AdjacencyList i) = i
+  type Edge (AdjacencyList i) = (i, i)
+  vertexMap = pure . propertyMap
+  edgeMap = pure . propertyMap
+
+instance Ix i => AdjacencyListGraph (AdjacencyList i) where
+  adjacentVertices v = AdjacencyList $ \g -> if inRange (bounds g) v 
+                                     then g ! v 
+                                     else []
+  source (a, _) = pure a
+  target (_, b) = pure b
+  outEdges = defaultOutEdges
diff --git a/src/Data/Graph/AdjacencyMatrix.hs b/src/Data/Graph/AdjacencyMatrix.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Graph/AdjacencyMatrix.hs
@@ -0,0 +1,56 @@
+{-# LANGUAGE TypeFamilies, FlexibleContexts #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Graph.Adjacency.Matrix
+-- Copyright   :  (C) 2011 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  type families
+--
+----------------------------------------------------------------------------
+
+module Data.Graph.AdjacencyMatrix
+  ( AdjacencyMatrix(..)
+  , ask
+  ) where
+
+import Control.Applicative
+import Data.Ix
+import Data.Array.IArray
+import Data.Graph.PropertyMap
+import Data.Graph.Class
+import Data.Graph.Class.AdjacencyMatrix
+
+newtype AdjacencyMatrix arr i a = AdjacencyMatrix { runAdjacencyMatrix :: arr (i,i) Bool -> a } 
+
+ask :: AdjacencyMatrix arr i (arr (i, i) Bool)
+ask = AdjacencyMatrix id
+
+instance Functor (AdjacencyMatrix arr i) where
+  fmap f (AdjacencyMatrix g) = AdjacencyMatrix (f . g)
+  b <$ _ = pure b
+
+instance Applicative (AdjacencyMatrix arr i) where
+  pure = AdjacencyMatrix . const
+  AdjacencyMatrix f <*> AdjacencyMatrix a = AdjacencyMatrix $ \t -> f t (a t)
+
+instance Monad (AdjacencyMatrix arr i) where
+  return = AdjacencyMatrix . const
+  AdjacencyMatrix f >>= k = AdjacencyMatrix $ \t -> runAdjacencyMatrix (k (f t)) t
+
+instance Ord i => Graph (AdjacencyMatrix arr i) where
+  type Vertex (AdjacencyMatrix arr i) = i
+  type Edge (AdjacencyMatrix arr i) = (i, i) 
+  vertexMap = pure . propertyMap
+  edgeMap = pure . propertyMap
+
+instance (IArray arr Bool, Ix i) => AdjacencyMatrixGraph (AdjacencyMatrix arr i) where
+  edge i j = AdjacencyMatrix $ \a ->
+    if inRange (bounds a) ix && (a ! ix) 
+    then Just ix
+    else Nothing
+    where ix = (i, j)
+
+
diff --git a/src/Data/Graph/Algorithm/BreadthFirstSearch.hs b/src/Data/Graph/Algorithm/BreadthFirstSearch.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Graph/Algorithm/BreadthFirstSearch.hs
@@ -0,0 +1,118 @@
+{-# LANGUAGE TypeFamilies #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Graph.Algorithm.BreadthFirstSearch
+-- Copyright   :  (C) 2011 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  type families
+--
+-- Breadth-first search
+----------------------------------------------------------------------------
+
+module Data.Graph.Algorithm.BreadthFirstSearch
+  ( bfs, Bfs(..)
+  ) where
+
+import Control.Applicative
+import Control.Monad
+import Control.Monad.Trans.Class
+import Control.Monad.Trans.State.Strict
+import Data.Foldable
+import Data.Monoid
+import Data.Sequence
+
+import Data.Graph.Class
+import Data.Graph.Class.AdjacencyList
+import Data.Graph.PropertyMap
+import Data.Graph.Internal.Color
+
+-- | Breadth first search visitor 
+data Bfs g m = Bfs 
+  { enterVertex :: Vertex g -> g m -- called the first time a vertex is discovered
+  , grayTarget  :: Edge g   -> g m -- called when we encounter a back edge to a vertex we're still processing
+  , exitVertex  :: Vertex g -> g m -- called once we have processed all descendants of a vertex
+  , blackTarget :: Edge g   -> g m -- called when we encounter a cross edge to a vertex we've already finished
+  } 
+
+instance Graph g => Functor (Bfs g) where
+  fmap f (Bfs a b c d) = Bfs 
+    (liftM f . a)
+    (liftM f . b)
+    (liftM f . c)
+    (liftM f . d)
+
+instance Graph g => Applicative (Bfs g) where
+  pure a = Bfs 
+    (const (return a))
+    (const (return a))
+    (const (return a))
+    (const (return a))
+
+  m <*> n = Bfs
+    (\v -> enterVertex m v `ap` enterVertex n v)
+    (\e -> grayTarget m e `ap`  grayTarget n e)
+    (\v -> exitVertex m v `ap`  exitVertex n v)
+    (\e -> blackTarget m e `ap` blackTarget n e)
+
+instance Graph g => Monad (Bfs g) where
+  return = pure
+  m >>= f = Bfs
+    (\v -> enterVertex m v >>= ($ v) . enterVertex . f)
+    (\e -> grayTarget m e >>= ($ e) . grayTarget . f)
+    (\v -> exitVertex m v >>= ($ v) . exitVertex . f)
+    (\e -> blackTarget m e >>= ($ e) . blackTarget . f)
+
+instance (Graph g, Monoid m) => Monoid (Bfs g m) where
+  mempty = return mempty
+  mappend = liftM2 mappend
+
+getS :: Monad g => k -> StateT (Seq v, PropertyMap g k Color) g Color
+getS k = do
+  m <- gets snd 
+  lift (getP m k)
+
+putS :: Monad g => k -> Color -> StateT (Seq v, PropertyMap g k Color) g ()
+putS k v = do
+  m <- gets snd 
+  m' <- lift $ putP m k v
+  modify $ \(q,_) -> (q, m')
+
+enqueue :: Graph g 
+        => Bfs g m 
+        -> Vertex g 
+        -> StateT (Seq (Vertex g), PropertyMap g (Vertex g) Color) g m
+enqueue vis v = do
+  m <- gets snd
+  m' <- lift $ putP m v Grey
+  modify $ \(q,_) -> (q |> v, m')
+  lift $ enterVertex vis v
+
+dequeue :: Monad g => StateT (Seq v, s) g r -> (v -> StateT (Seq v, s) g r) -> StateT (Seq v, s) g r
+dequeue ke ks = do
+  (q, m) <- get
+  case viewl q of
+    EmptyL -> ke
+    (a :< q') -> put (q', m) >> ks a
+
+bfs :: (AdjacencyListGraph g, Monoid m) => Bfs g m -> Vertex g -> g m
+bfs vis v0 = do
+  m <- vertexMap White 
+  evalStateT (enqueue vis v0 >>= pump) (mempty, m) 
+  where
+  pump lhs = dequeue (return lhs) $ \ v -> do
+    adjs <- lift $ outEdges v
+    children <- foldrM 
+      (\e m -> do
+        v' <- target e
+        color <- getS v'
+        liftM (`mappend` m) $ case color of
+          White -> enqueue vis v' 
+          Grey -> lift $ grayTarget vis e
+          Black -> lift $ blackTarget vis e
+      ) mempty adjs
+    putS v Black
+    rhs <- lift $ exitVertex vis v 
+    pump $ lhs `mappend` children `mappend` rhs
diff --git a/src/Data/Graph/Algorithm/DepthFirstSearch.hs b/src/Data/Graph/Algorithm/DepthFirstSearch.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Graph/Algorithm/DepthFirstSearch.hs
@@ -0,0 +1,103 @@
+{-# LANGUAGE TypeFamilies #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Graph.Algorithm.DepthFirstSearch
+-- Copyright   :  (C) 2011 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  type families
+--
+-- Depth-first search
+----------------------------------------------------------------------------
+
+module Data.Graph.Algorithm.DepthFirstSearch
+  ( dfs, Dfs(..)
+  ) where
+
+import Control.Applicative
+import Control.Monad
+import Control.Monad.Trans.Class
+import Control.Monad.Trans.State.Strict
+import Data.Foldable
+import Data.Monoid
+
+import Data.Graph.Class
+import Data.Graph.Class.AdjacencyList
+import Data.Graph.PropertyMap
+import Data.Graph.Internal.Color
+
+data Dfs g m = Dfs 
+  { enterVertex :: Vertex g -> g m -- called the first time a vertex is discovered
+  , grayTarget  :: Edge g   -> g m -- called when we encounter a back edge to a vertex we're still processing
+  , exitVertex  :: Vertex g -> g m -- called once we have processed all descendants of a vertex
+  , blackTarget :: Edge g   -> g m -- called when we encounter a cross edge to a vertex we've already finished
+  }
+
+instance Graph g => Functor (Dfs g) where
+  fmap f (Dfs a b c d) = Dfs 
+    (liftM f . a)
+    (liftM f . b)
+    (liftM f . c)
+    (liftM f . d)
+
+instance Graph g => Applicative (Dfs g) where
+  pure a = Dfs 
+    (const (return a))
+    (const (return a))
+    (const (return a))
+    (const (return a))
+
+  m <*> n = Dfs
+    (\v -> enterVertex m v `ap` enterVertex n v)
+    (\e -> grayTarget m e `ap`  grayTarget n e)
+    (\v -> exitVertex m v `ap`  exitVertex n v)
+    (\e -> blackTarget m e `ap` blackTarget n e)
+
+instance Graph g => Monad (Dfs g) where
+  return = pure
+  m >>= f = Dfs
+    (\v -> enterVertex m v >>= ($ v) . enterVertex . f)
+    (\e -> grayTarget m e >>= ($ e) . grayTarget . f)
+    (\v -> exitVertex m v >>= ($ v) . exitVertex . f)
+    (\e -> blackTarget m e >>= ($ e) . blackTarget . f)
+
+instance (Graph g, Monoid m) => Monoid (Dfs g m) where
+  mempty = return mempty
+  mappend = liftM2 mappend
+
+getS :: Monad g => k -> StateT (PropertyMap g k v) g v
+getS k = do
+  m <- get 
+  lift (getP m k)
+
+putS :: Monad g => k -> v -> StateT (PropertyMap g k v) g ()
+putS k v = do
+  m <- get 
+  m' <- lift $ putP m k v
+  put m'
+
+-- TODO: CPS transform?
+dfs :: (AdjacencyListGraph g, Monoid m) => Dfs g m -> Vertex g -> g m
+dfs vis v0 = do
+  m <- vertexMap White 
+  evalStateT (go v0) m where
+  go v = do
+    putS v Grey
+    lhs <- lift $ enterVertex vis v
+    adjs <- lift $ outEdges v 
+    result <- foldrM 
+      (\e m -> do 
+        v' <- target e
+        color <- getS v'
+        liftM (`mappend` m) $ case color of
+          White -> go v'
+          Grey  -> lift $ grayTarget vis e
+          Black -> lift $ blackTarget vis e
+      ) 
+      mempty 
+      adjs
+    putS v Black
+    rhs <- lift $ exitVertex vis v
+    return $ lhs `mappend` result `mappend` rhs
diff --git a/src/Data/Graph/Class.hs b/src/Data/Graph/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Graph/Class.hs
@@ -0,0 +1,127 @@
+{-# LANGUAGE TypeFamilies, FlexibleContexts #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Graph.Class
+-- Copyright   :  (C) 2011 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  type families
+--
+----------------------------------------------------------------------------
+
+module Data.Graph.Class 
+  ( Graph(..)
+  , VertexMap
+  , EdgeMap
+  , liftVertexMap
+  , liftEdgeMap
+  ) where
+
+import Control.Monad
+import qualified Control.Monad.Trans.State.Strict as Strict
+import qualified Control.Monad.Trans.State.Lazy as Lazy
+import qualified Control.Monad.Trans.Writer.Strict as Strict
+import qualified Control.Monad.Trans.Writer.Lazy as Lazy
+import qualified Control.Monad.Trans.RWS.Strict as Strict
+import qualified Control.Monad.Trans.RWS.Lazy as Lazy
+import Control.Monad.Trans.Identity
+import Control.Monad.Trans.Maybe
+import Control.Monad.Trans.Error
+import Control.Monad.Trans.Reader 
+import Control.Monad.Trans.Class
+import Data.Functor.Identity
+import Data.Monoid
+import Data.Graph.PropertyMap
+import Data.Void
+
+type VertexMap g = PropertyMap g (Vertex g)
+type EdgeMap g = PropertyMap g (Edge g)
+
+class (Monad g, Eq (Vertex g), Eq (Edge g)) => Graph g where
+  type Vertex g :: *
+  type Edge g :: * 
+  vertexMap :: a -> g (VertexMap g a)
+  edgeMap   :: a -> g (EdgeMap g a)
+
+liftVertexMap :: (MonadTrans t, Graph (t g), Graph g, Vertex (t g) ~ Vertex g) 
+              => a -> t g (VertexMap (t g) a)
+liftVertexMap = lift . liftM liftPropertyMap . vertexMap
+{-# INLINE liftVertexMap #-}
+
+liftEdgeMap :: (MonadTrans t, Graph (t g), Graph g, Edge (t g) ~ Edge g) 
+            => a -> t g (EdgeMap (t g) a)
+liftEdgeMap = lift . liftM liftPropertyMap . edgeMap
+{-# INLINE liftEdgeMap #-}
+
+instance Graph g => Graph (Strict.StateT s g) where
+  type Vertex (Strict.StateT s g) = Vertex g
+  type Edge (Strict.StateT s g) = Edge g
+  vertexMap = liftVertexMap
+  edgeMap = liftEdgeMap
+
+instance Graph g => Graph (Lazy.StateT s g) where
+  type Vertex (Lazy.StateT s g) = Vertex g
+  type Edge (Lazy.StateT s g) = Edge g
+  vertexMap = liftVertexMap
+  edgeMap = liftEdgeMap
+
+instance (Graph g, Monoid m) => Graph (Strict.WriterT m g) where
+  type Vertex (Strict.WriterT m g) = Vertex g
+  type Edge (Strict.WriterT m g) = Edge g
+  vertexMap = liftVertexMap
+  edgeMap = liftEdgeMap
+
+instance (Graph g, Monoid m) => Graph (Lazy.WriterT m g) where
+  type Vertex (Lazy.WriterT m g) = Vertex g
+  type Edge (Lazy.WriterT m g) = Edge g
+  vertexMap = liftVertexMap
+  edgeMap = liftEdgeMap
+
+instance Graph g => Graph (ReaderT m g) where
+  type Vertex (ReaderT m g) = Vertex g 
+  type Edge (ReaderT m g) = Edge g
+  vertexMap = liftVertexMap
+  edgeMap = liftEdgeMap
+
+instance Graph g => Graph (IdentityT g) where
+  type Vertex (IdentityT g) = Vertex g
+  type Edge (IdentityT g) = Edge g
+  vertexMap = liftVertexMap
+  edgeMap = liftEdgeMap
+
+instance Graph g => Graph (MaybeT g) where
+  type Vertex (MaybeT g) = Vertex g
+  type Edge (MaybeT g) = Edge g
+  vertexMap = liftVertexMap
+  edgeMap = liftEdgeMap
+
+instance (Graph g, Error e) => Graph (ErrorT e g) where
+  type Vertex (ErrorT e g) = Vertex g
+  type Edge (ErrorT e g) = Edge g
+  vertexMap = liftVertexMap
+  edgeMap = liftEdgeMap
+
+instance (Graph g, Monoid w) => Graph (Lazy.RWST r w s g) where
+  type Vertex (Lazy.RWST r w s g) = Vertex g
+  type Edge (Lazy.RWST r w s g) = Edge g
+  vertexMap = liftVertexMap
+  edgeMap = liftEdgeMap
+
+instance (Graph g, Monoid w) => Graph (Strict.RWST r w s g) where
+  type Vertex (Strict.RWST r w s g) = Vertex g
+  type Edge (Strict.RWST r w s g) = Edge g
+  vertexMap = liftVertexMap
+  edgeMap = liftEdgeMap
+
+voidMap :: PropertyMap Identity Void a
+voidMap = PropertyMap (Identity . absurd) $ \_ _ -> Identity voidMap
+
+-- | The empty graph
+instance Graph Identity where
+  type Vertex Identity = Void
+  type Edge Identity = Void
+  vertexMap _ = Identity voidMap 
+  edgeMap   _ = Identity voidMap
+
diff --git a/src/Data/Graph/Class/AdjacencyList.hs b/src/Data/Graph/Class/AdjacencyList.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Graph/Class/AdjacencyList.hs
@@ -0,0 +1,129 @@
+{-# LANGUAGE TypeFamilies, FlexibleInstances #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Graph.Class.AdjacencyList
+-- Copyright   :  (C) 2011 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  type families
+--
+----------------------------------------------------------------------------
+
+module Data.Graph.Class.AdjacencyList
+  ( AdjacencyListGraph(..)
+  , defaultOutEdges
+  , module Data.Graph.Class
+  ) where
+
+import Control.Monad
+import Control.Monad.Trans.Class
+import qualified Control.Monad.Trans.State.Strict as Strict
+import qualified Control.Monad.Trans.State.Lazy as Lazy
+import qualified Control.Monad.Trans.Writer.Strict as Strict
+import qualified Control.Monad.Trans.Writer.Lazy as Lazy
+import qualified Control.Monad.Trans.RWS.Strict as Strict
+import qualified Control.Monad.Trans.RWS.Lazy as Lazy
+import Control.Monad.Trans.Identity
+import Control.Monad.Trans.Maybe
+import Control.Monad.Trans.Error
+import Control.Monad.Trans.Reader
+import Data.Functor.Identity
+import Data.Monoid
+import Data.Graph.Class
+
+defaultOutEdges :: AdjacencyListGraph g => Vertex g -> g [(Vertex g, Vertex g)]
+defaultOutEdges v = liftM (map ((,) v)) (adjacentVertices v)
+
+-- | Minimal definition: 'source', 'target', and either 'adjacentVertices' with @'outEdges' = 'defaultOutEdges'@ or 'outEdges'
+class Graph g => AdjacencyListGraph g where
+  -- /O(1)/
+  source :: Edge g -> g (Vertex g)
+  -- /O(1)/
+  target :: Edge g -> g (Vertex g)
+  -- /O(e)/ in the number of out edges
+  outEdges :: Vertex g -> g [Edge g]
+
+  -- /O(e)/
+  outDegree :: Vertex g -> g Int
+  outDegree v = liftM length (outEdges v)
+
+  adjacentVertices :: Vertex g -> g [Vertex g]
+  adjacentVertices = outEdges >=> mapM target
+
+instance AdjacencyListGraph g => AdjacencyListGraph (Strict.StateT s g) where
+  adjacentVertices = lift . adjacentVertices
+  source = lift . source
+  target = lift . target
+  outEdges = lift . outEdges
+  outDegree = lift . outDegree
+
+instance AdjacencyListGraph g => AdjacencyListGraph (Lazy.StateT s g) where
+  adjacentVertices = lift . adjacentVertices
+  source = lift . source
+  target = lift . target
+  outEdges = lift . outEdges
+  outDegree = lift . outDegree
+
+instance (AdjacencyListGraph g, Monoid m) => AdjacencyListGraph (Strict.WriterT m g) where
+  adjacentVertices = lift . adjacentVertices
+  source = lift . source
+  target = lift . target
+  outEdges = lift . outEdges
+  outDegree = lift . outDegree
+
+instance (AdjacencyListGraph g, Monoid m) => AdjacencyListGraph (Lazy.WriterT m g) where
+  adjacentVertices = lift . adjacentVertices
+  source = lift . source
+  target = lift . target
+  outEdges = lift . outEdges
+  outDegree = lift . outDegree
+
+instance (AdjacencyListGraph g, Monoid m) => AdjacencyListGraph (Strict.RWST r m s g) where
+  adjacentVertices = lift . adjacentVertices
+  source = lift . source
+  target = lift . target
+  outEdges = lift . outEdges
+  outDegree = lift . outDegree
+
+instance (AdjacencyListGraph g, Monoid m) => AdjacencyListGraph (Lazy.RWST r m s g) where
+  adjacentVertices = lift . adjacentVertices
+  source = lift . source
+  target = lift . target
+  outEdges = lift . outEdges
+  outDegree = lift . outDegree
+
+instance AdjacencyListGraph g => AdjacencyListGraph (ReaderT e g) where
+  adjacentVertices = lift . adjacentVertices
+  source = lift . source
+  target = lift . target
+  outEdges = lift . outEdges
+  outDegree = lift . outDegree
+
+instance (AdjacencyListGraph g, Error e) => AdjacencyListGraph (ErrorT e g) where
+  adjacentVertices = lift . adjacentVertices
+  source = lift . source
+  target = lift . target
+  outEdges = lift . outEdges
+  outDegree = lift . outDegree
+
+instance AdjacencyListGraph g => AdjacencyListGraph (MaybeT g) where
+  adjacentVertices = lift . adjacentVertices
+  source = lift . source
+  target = lift . target
+  outEdges = lift . outEdges
+  outDegree = lift . outDegree
+
+instance AdjacencyListGraph g => AdjacencyListGraph (IdentityT g) where
+  adjacentVertices = lift . adjacentVertices
+  source = lift . source
+  target = lift . target
+  outEdges = lift . outEdges
+  outDegree = lift . outDegree
+
+instance AdjacencyListGraph Identity where
+  source = Identity
+  target = Identity
+  outEdges _ = Identity []
+  outDegree _ = Identity 0
diff --git a/src/Data/Graph/Class/AdjacencyMatrix.hs b/src/Data/Graph/Class/AdjacencyMatrix.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Graph/Class/AdjacencyMatrix.hs
@@ -0,0 +1,68 @@
+{-# LANGUAGE TypeFamilies, FlexibleInstances #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Graph.Class.AdjacencyMatrix
+-- Copyright   :  (C) 2011 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  type families
+--
+----------------------------------------------------------------------------
+
+module Data.Graph.Class.AdjacencyMatrix
+  ( AdjacencyMatrixGraph(..)
+  , module Data.Graph.Class
+  ) where
+
+import qualified Control.Monad.Trans.State.Strict as Strict
+import qualified Control.Monad.Trans.State.Lazy as Lazy
+import qualified Control.Monad.Trans.Writer.Strict as Strict
+import qualified Control.Monad.Trans.Writer.Lazy as Lazy
+import qualified Control.Monad.Trans.RWS.Strict as Strict
+import qualified Control.Monad.Trans.RWS.Lazy as Lazy
+import Control.Monad.Trans.Reader
+import Control.Monad.Trans.Maybe
+import Control.Monad.Trans.Identity
+import Control.Monad.Trans.Error
+import Control.Monad.Trans.Class
+import Data.Functor.Identity
+import Data.Monoid
+import Data.Graph.Class
+
+class Graph g => AdjacencyMatrixGraph g where
+  edge :: Vertex g -> Vertex g -> g (Maybe (Edge g))
+
+instance AdjacencyMatrixGraph g => AdjacencyMatrixGraph (Strict.StateT s g) where
+  edge a b = lift (edge a b)
+
+instance AdjacencyMatrixGraph g => AdjacencyMatrixGraph (Lazy.StateT s g) where
+  edge a b = lift (edge a b)
+
+instance (AdjacencyMatrixGraph g, Monoid m) => AdjacencyMatrixGraph (Strict.WriterT m g) where
+  edge a b = lift (edge a b)
+
+instance (AdjacencyMatrixGraph g, Monoid m) => AdjacencyMatrixGraph (Lazy.WriterT m g) where
+  edge a b = lift (edge a b)
+
+instance (AdjacencyMatrixGraph g, Monoid m) => AdjacencyMatrixGraph (Strict.RWST r m s g) where
+  edge a b = lift (edge a b)
+
+instance (AdjacencyMatrixGraph g, Monoid m) => AdjacencyMatrixGraph (Lazy.RWST r m s g) where
+  edge a b = lift (edge a b)
+
+instance AdjacencyMatrixGraph g => AdjacencyMatrixGraph (MaybeT g) where
+  edge a b = lift (edge a b)
+
+instance (AdjacencyMatrixGraph g, Error e) => AdjacencyMatrixGraph (ErrorT e g) where
+  edge a b = lift (edge a b)
+
+instance AdjacencyMatrixGraph g => AdjacencyMatrixGraph (IdentityT g) where
+  edge a b = lift (edge a b)
+
+instance AdjacencyMatrixGraph g => AdjacencyMatrixGraph (ReaderT e g) where
+  edge a b = lift (edge a b)
+
+instance AdjacencyMatrixGraph Identity where
+  edge _ _ = Identity Nothing
diff --git a/src/Data/Graph/Class/Bidirectional.hs b/src/Data/Graph/Class/Bidirectional.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Graph/Class/Bidirectional.hs
@@ -0,0 +1,113 @@
+{-# LANGUAGE TypeFamilies, FlexibleInstances #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Graph.Class.Bidirectional
+-- Copyright   :  (C) 2011 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  type families
+--
+----------------------------------------------------------------------------
+
+module Data.Graph.Class.Bidirectional 
+  ( BidirectionalGraph(..)
+  , module Data.Graph.Class.AdjacencyList
+  ) where
+
+import Control.Monad
+import Control.Monad.Trans.Class
+import qualified Control.Monad.Trans.State.Strict as Strict
+import qualified Control.Monad.Trans.State.Lazy as Lazy
+import qualified Control.Monad.Trans.Writer.Strict as Strict
+import qualified Control.Monad.Trans.Writer.Lazy as Lazy
+import qualified Control.Monad.Trans.RWS.Strict as Strict
+import qualified Control.Monad.Trans.RWS.Lazy as Lazy
+import Control.Monad.Trans.Reader
+import Control.Monad.Trans.Identity
+import Control.Monad.Trans.Maybe
+import Control.Monad.Trans.Error
+import Data.Functor.Identity
+import Data.Monoid
+import Data.Graph.Class.AdjacencyList
+
+class AdjacencyListGraph g => BidirectionalGraph g where
+  -- /O(e)/
+  inEdges :: Vertex g -> g [Edge g]
+  -- /O(e)/
+  inDegree :: Vertex g -> g Int
+  inDegree v = length `liftM` inEdges v
+  
+  incidentEdges :: Vertex g -> g [Edge g]
+  incidentEdges v = liftM2 (++) (inEdges v) (outEdges v)
+
+  degree :: Vertex g -> g Int
+  degree v = liftM2 (+) (inDegree v) (outDegree v)
+
+instance BidirectionalGraph g => BidirectionalGraph (Strict.StateT s g) where
+  inEdges  = lift . inEdges
+  inDegree = lift . inDegree
+  incidentEdges = lift . incidentEdges
+  degree = lift . degree
+
+instance BidirectionalGraph g => BidirectionalGraph (Lazy.StateT s g) where
+  inEdges  = lift . inEdges
+  inDegree = lift . inDegree
+  incidentEdges = lift . incidentEdges
+  degree = lift . degree
+
+instance (BidirectionalGraph g, Monoid m) => BidirectionalGraph (Strict.WriterT m g) where
+  inEdges  = lift . inEdges
+  inDegree = lift . inDegree
+  incidentEdges = lift . incidentEdges
+  degree = lift . degree
+
+instance (BidirectionalGraph g, Monoid m) => BidirectionalGraph (Lazy.WriterT m g) where
+  inEdges  = lift . inEdges
+  inDegree = lift . inDegree
+  incidentEdges = lift . incidentEdges
+  degree = lift . degree
+
+instance (BidirectionalGraph g, Monoid m) => BidirectionalGraph (Strict.RWST r m s g) where
+  inEdges  = lift . inEdges
+  inDegree = lift . inDegree
+  incidentEdges = lift . incidentEdges
+  degree = lift . degree
+
+instance (BidirectionalGraph g, Monoid m) => BidirectionalGraph (Lazy.RWST r m s g) where
+  inEdges  = lift . inEdges
+  inDegree = lift . inDegree
+  incidentEdges = lift . incidentEdges
+  degree = lift . degree
+
+instance BidirectionalGraph g => BidirectionalGraph (ReaderT e g) where
+  inEdges  = lift . inEdges
+  inDegree = lift . inDegree
+  incidentEdges = lift . incidentEdges
+  degree = lift . degree
+
+instance BidirectionalGraph g => BidirectionalGraph (IdentityT g) where
+  inEdges  = lift . inEdges
+  inDegree = lift . inDegree
+  incidentEdges = lift . incidentEdges
+  degree = lift . degree
+
+instance BidirectionalGraph g => BidirectionalGraph (MaybeT g) where
+  inEdges  = lift . inEdges
+  inDegree = lift . inDegree
+  incidentEdges = lift . incidentEdges
+  degree = lift . degree
+
+instance (BidirectionalGraph g, Error e) => BidirectionalGraph (ErrorT e g) where
+  inEdges  = lift . inEdges
+  inDegree = lift . inDegree
+  incidentEdges = lift . incidentEdges
+  degree = lift . degree
+
+instance BidirectionalGraph Identity where
+  inEdges _ = Identity []
+  inDegree _ = Identity 0
+  incidentEdges _ = Identity []
+  degree _  = Identity 0
+
diff --git a/src/Data/Graph/Class/EdgeEnumerable.hs b/src/Data/Graph/Class/EdgeEnumerable.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Graph/Class/EdgeEnumerable.hs
@@ -0,0 +1,69 @@
+{-# LANGUAGE TypeFamilies, FlexibleContexts #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Graph.Class.EdgeEnumerable
+-- Copyright   :  (C) 2011 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  type families
+--
+----------------------------------------------------------------------------
+
+module Data.Graph.Class.EdgeEnumerable
+  ( EdgeEnumerableGraph(..)
+  , module Data.Graph.Class
+  ) where
+
+import qualified Control.Monad.Trans.State.Strict as Strict
+import qualified Control.Monad.Trans.State.Lazy as Lazy
+import qualified Control.Monad.Trans.Writer.Strict as Strict
+import qualified Control.Monad.Trans.Writer.Lazy as Lazy
+import qualified Control.Monad.Trans.RWS.Strict as Strict
+import qualified Control.Monad.Trans.RWS.Lazy as Lazy
+import Control.Monad.Trans.Reader
+import Control.Monad.Trans.Identity
+import Control.Monad.Trans.Maybe
+import Control.Monad.Trans.Error
+import Control.Monad.Trans.Class
+import Data.Functor.Identity
+import Data.Monoid
+import Data.Graph.Class
+
+class Graph g => EdgeEnumerableGraph g where
+  -- | /O(e)/
+  edges :: g [Edge g]
+
+instance EdgeEnumerableGraph g => EdgeEnumerableGraph (Strict.StateT s g) where
+  edges = lift edges
+
+instance EdgeEnumerableGraph g => EdgeEnumerableGraph (Lazy.StateT s g) where
+  edges = lift edges
+
+instance (EdgeEnumerableGraph g, Monoid m) => EdgeEnumerableGraph (Strict.WriterT m g) where
+  edges = lift edges
+
+instance (EdgeEnumerableGraph g, Monoid m) => EdgeEnumerableGraph (Lazy.WriterT m g) where
+  edges = lift edges
+
+instance (EdgeEnumerableGraph g, Monoid m) => EdgeEnumerableGraph (Strict.RWST r m s g) where
+  edges = lift edges
+
+instance (EdgeEnumerableGraph g, Monoid m) => EdgeEnumerableGraph (Lazy.RWST r m s g) where
+  edges = lift edges
+
+instance EdgeEnumerableGraph g => EdgeEnumerableGraph (MaybeT g) where
+  edges = lift edges
+
+instance EdgeEnumerableGraph g => EdgeEnumerableGraph (IdentityT g) where
+  edges = lift edges
+
+instance (EdgeEnumerableGraph g, Error e) => EdgeEnumerableGraph (ErrorT e g) where
+  edges = lift edges
+
+instance EdgeEnumerableGraph g => EdgeEnumerableGraph (ReaderT e g) where
+  edges = lift edges
+
+instance EdgeEnumerableGraph Identity where
+  edges = Identity []
diff --git a/src/Data/Graph/Class/VertexEnumerable.hs b/src/Data/Graph/Class/VertexEnumerable.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Graph/Class/VertexEnumerable.hs
@@ -0,0 +1,69 @@
+{-# LANGUAGE TypeFamilies, FlexibleContexts #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Graph.Class.VertexEnumerable
+-- Copyright   :  (C) 2011 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  type families
+--
+----------------------------------------------------------------------------
+
+module Data.Graph.Class.VertexEnumerable
+  ( VertexEnumerableGraph(..)
+  , module Data.Graph.Class
+  ) where
+
+import qualified Control.Monad.Trans.State.Strict as Strict
+import qualified Control.Monad.Trans.State.Lazy as Lazy
+import qualified Control.Monad.Trans.Writer.Strict as Strict
+import qualified Control.Monad.Trans.Writer.Lazy as Lazy
+import qualified Control.Monad.Trans.RWS.Strict as Strict
+import qualified Control.Monad.Trans.RWS.Lazy as Lazy
+import Control.Monad.Trans.Identity
+import Control.Monad.Trans.Maybe
+import Control.Monad.Trans.Error
+import Control.Monad.Trans.Class
+import Control.Monad.Trans.Reader
+import Data.Monoid
+import Data.Graph.Class
+import Data.Functor.Identity
+
+class Graph g => VertexEnumerableGraph g where
+  -- | /O(v)/
+  vertices :: g [Vertex g]
+
+instance VertexEnumerableGraph g => VertexEnumerableGraph (Strict.StateT s g) where
+  vertices = lift vertices
+
+instance VertexEnumerableGraph g => VertexEnumerableGraph (Lazy.StateT s g) where
+  vertices = lift vertices
+
+instance (VertexEnumerableGraph g, Monoid m) => VertexEnumerableGraph (Strict.WriterT m g) where
+  vertices = lift vertices
+
+instance (VertexEnumerableGraph g, Monoid m) => VertexEnumerableGraph (Lazy.WriterT m g) where
+  vertices = lift vertices
+
+instance (VertexEnumerableGraph g, Monoid m) => VertexEnumerableGraph (Strict.RWST r m s g) where
+  vertices = lift vertices
+  
+instance (VertexEnumerableGraph g, Monoid m) => VertexEnumerableGraph (Lazy.RWST r m s g) where
+  vertices = lift vertices
+
+instance VertexEnumerableGraph g => VertexEnumerableGraph (MaybeT g) where
+  vertices = lift vertices
+
+instance VertexEnumerableGraph g => VertexEnumerableGraph (IdentityT g) where
+  vertices = lift vertices
+
+instance (VertexEnumerableGraph g, Error e) => VertexEnumerableGraph (ErrorT e g) where
+  vertices = lift vertices
+
+instance VertexEnumerableGraph g => VertexEnumerableGraph (ReaderT m g) where
+  vertices = lift vertices
+
+instance VertexEnumerableGraph Identity where
+  vertices = Identity []
diff --git a/src/Data/Graph/Dual.hs b/src/Data/Graph/Dual.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Graph/Dual.hs
@@ -0,0 +1,73 @@
+{-# LANGUAGE TypeFamilies, FlexibleContexts #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Graph.Dual
+-- Copyright   :  (C) 2011 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  type families
+--
+----------------------------------------------------------------------------
+
+module Data.Graph.Dual
+  ( Dual(..)
+  ) where
+
+import Control.Applicative
+import Control.Monad
+import Control.Monad.Trans.Class
+import Data.Graph.PropertyMap
+import Data.Graph.Class.AdjacencyList
+import Data.Graph.Class.AdjacencyMatrix
+import Data.Graph.Class.EdgeEnumerable
+import Data.Graph.Class.VertexEnumerable
+import Data.Graph.Class.Bidirectional
+
+newtype Dual g a = Dual { runDual :: g a }
+
+instance MonadTrans Dual where
+  lift = Dual
+
+instance Functor g => Functor (Dual g) where
+  fmap f (Dual g) = Dual $ fmap f g
+  b <$ Dual g = Dual $ b <$ g
+
+instance Applicative g => Applicative (Dual g) where
+  pure = Dual . pure
+  Dual f <*> Dual a = Dual (f <*> a)
+  Dual f <*  Dual a = Dual (f <*  a)
+  Dual f  *> Dual a = Dual (f  *> a)
+
+instance Monad g => Monad (Dual g) where
+  return = Dual . return
+  Dual g >>= k = Dual (g >>= runDual . k)
+  Dual g >> Dual h = Dual (g >> h)
+
+instance Graph g => Graph (Dual g) where
+  type Vertex (Dual g) = Vertex g
+  type Edge (Dual g) = Edge g
+  vertexMap = Dual . liftM liftPropertyMap . vertexMap
+  edgeMap   = Dual . liftM liftPropertyMap . edgeMap
+
+instance AdjacencyMatrixGraph g => AdjacencyMatrixGraph (Dual g) where
+  edge l r = Dual (edge r l)
+
+instance BidirectionalGraph g => AdjacencyListGraph (Dual g) where
+  source = Dual . target
+  target = Dual . source
+  outEdges = Dual . inEdges
+  outDegree = Dual . inDegree
+
+instance BidirectionalGraph g => BidirectionalGraph (Dual g) where
+  inEdges = Dual . outEdges
+  inDegree = Dual . inDegree
+  incidentEdges = Dual . incidentEdges
+  degree = Dual . degree
+
+instance EdgeEnumerableGraph g => EdgeEnumerableGraph (Dual g) where
+  edges = Dual edges 
+
+instance VertexEnumerableGraph g => VertexEnumerableGraph (Dual g) where
+  vertices = Dual vertices
diff --git a/src/Data/Graph/Internal/Color.hs b/src/Data/Graph/Internal/Color.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Graph/Internal/Color.hs
@@ -0,0 +1,3 @@
+module Data.Graph.Internal.Color where
+
+data Color = White | Grey | Black deriving (Eq,Ord,Show,Read)
diff --git a/src/Data/Graph/PropertyMap.hs b/src/Data/Graph/PropertyMap.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Graph/PropertyMap.hs
@@ -0,0 +1,69 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Graph.PropertyMap
+-- Copyright   :  (C) 2011 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  portable
+--
+-- Total transient monadic maps, used to track information about vertices
+-- and edges in a graph
+----------------------------------------------------------------------------
+
+module Data.Graph.PropertyMap 
+  ( PropertyMap(..)
+  , modifyP
+  , intPropertyMap
+  , propertyMap
+  , liftPropertyMap
+  ) where
+
+import Control.Monad
+import Control.Monad.Trans.Class
+import qualified Data.IntMap as IntMap
+import qualified Data.Map as Map
+
+data PropertyMap m k v = PropertyMap
+  { getP :: k -> m v
+  , putP :: k -> v -> m (PropertyMap m k v)
+  }
+
+modifyP :: Monad m => PropertyMap m k v -> k -> (v -> v) -> m (PropertyMap m k v)
+modifyP m k f = do
+  a <- getP m k
+  putP m k (f a)
+
+-- A pure IntMap-backed vertex map
+intPropertyMap :: Monad m => v -> PropertyMap m Int v
+intPropertyMap v0 = go v0 IntMap.empty where
+  go v m = PropertyMap 
+    { getP = \k -> return $ maybe v id (IntMap.lookup k m)
+    , putP = \k v' -> return $ go v (IntMap.insert k v' m)
+    }
+
+-- A pure Map-backed vertex map
+propertyMap :: (Monad m, Ord k) => v -> PropertyMap m k v
+propertyMap v0 = go v0 Map.empty where
+  go v m = PropertyMap 
+    { getP = \k -> return $ maybe v id (Map.lookup k m)
+    , putP = \k v' -> return $ go v (Map.insert k v' m)
+    }
+
+liftPropertyMap :: (MonadTrans t, Monad m, Monad (t m)) => PropertyMap m k v -> PropertyMap (t m) k v
+liftPropertyMap (PropertyMap g p) = PropertyMap (lift . g) (\k v -> liftPropertyMap `liftM` lift (p k v))
+
+{-
+-- An impure STArray-backed vertex map
+stAdjVertexMap :: (DenseAdjacencyMatrix g, MonadST s g) => a -> g (PropertyMap g (Vertex g) a)
+stAdjVertexMap v0 = do
+  range <- vertexRange 
+  arr <- newSTArray range v0
+  return $ go arr
+  where
+    go arr = r where r = VertexMap
+      { getP = readSTArray arr
+      , putP = \k v -> writeSTArray arr k v >> return r
+      } 
+-}
