Thomas Bereknyei, Edward Kmett and Alp Mestanogullari started working a on a new version of HNN, which probably requires a nicer graph library. Here is a draft of the latter. {{{ {-# LANGUAGE RankNTypes #-} -- a tiny annotated graph library -- Edward Kmett 2010 module Data.Graph.Annotated where import Data.Sequence as S import Data.Sequence (Sequence, ViewL(..), ViewR(..), (><)) import Data.Vector as V import Data.Ix import qualified Data.Graph as G import Data.Graph (Graph) import Control.Monad.Writer.Instances class PFunctor f where first :: (a -> b) -> f a c -> f b c -- a simple safe graph library based on Data.Graph for prototyping -- TODO: use Vector [Int] or Rope (Vector [Int]) newtype Graph b = Graph { runGraph :: G.Graph } newtype Vertex b = Vertex { vertexId :: Int } deriving (Enum,Ix,Eq,Ord,Show,Typeable) vertices :: Graph b -> [Vertex b] vertices = fmap Vertex . G.vertices . runGraph dfs :: Graph b -> [Vertex b] -> Forest (Vertex b) dfs g vs = fmap Vertex <$> G.dfs (runGraph g) (vertexId <$> vs) dff :: Graph b -> Forest (Vertex b) dff g = Vertex <$> G.dff (runGraph g) topSort :: Graph b -> [Vertex b] topSort g = Vertex <$> G.topSort (runGraph g) components :: Graph b -> Forest (Vertex b) components g = fmap Vertex <$> G.components (runGraph g) newtype Edge b = Edge (Vertex b, Vertex b) deriving (Ix,Eq,Ord,Show,Typeable) edges :: Graph b -> [Edge b] edges = fmap Edge . G.edges . runGraph newtype NodeAnn a b = NodeAnn (G.Table a) instance PFunctor NodeAnn where first f (NodeAnn t) = NodeAnn (f <$> t) indegree :: Graph b -> NodeAnn Int b indegree = NodeAnn . G.indegree . runGraph outdegree :: Graph b -> NodeAnn Int b outdegree = NodeAnn . G.outdegree . runGraph data Degree b = Degree { indegree :: NodeAnn Int b, outDegree :: NodeAnn Int b } degree :: Graph b -> (Degree `Annotated` Graph) b degree g = (g, Degree (indegree g) (outdegree g)) -- newtype NodeMap k b = NodeAnn (Map k IntSet) (IntMap [k]) -- tag :: Ord k => k -> Vertex b -> NodeMap k b -> NodeMap k b -- lookup :: NodeMap k b -> k -> [Vertex b] -- used internally, expose? class Functor w => Comonad w where extract :: w a -> a extend :: (w a -> b) -> w a -> w b duplicate :: w a -> w (w a) duplicate = extend id extend f = fmap f . duplicate instance Comonad ((,)e) where extract = snd extend f ea = (fst ea, f ea) duplicate f ea@(e,_) = (e, f ea) type Annotated f s b = (s b, f b) -- existentially wrapped annotation -- data Ann f s = forall b. Ann ((f `Annotated` s) b) -- runAnn :: Ann f s -> (forall b. (f `Annotated` s) b -> r) -> r -- runAnn (Ann a) k = k a -- a boxed up annotated structure newtype Ann f s = Ann { runAnn :: forall r. (forall b. (f `Annotated` s) b -> r) -> r } -- we can transpose node annotations easily data Transpose b class TransposableAnn f where transposeAnn :: (f `Annotated` Graph) a -> f (Transpose a) instance TransposableAnn (NodeAnn a) where transposeAnn (NodeAnn t) = NodeAnn t transpose :: TransposableAnn f => (f `Annotated` Graph) b -> (f `Annotated` Graph) (Transpose b) transpose g = (G.transpose (runGraph g), transposeAnn g) }}}