@@ -0,0 +1,87 @@
1+-- | Representation of a directed graph. In Hakyll, this is used for dependency
4+module Hakyll.Core.DirectedGraph
13+import Prelude hiding (reverse, filter)
14+import Data.Monoid (mconcat)
16+import Data.Maybe (fromMaybe)
17+import qualified Data.Map as M
18+import qualified Data.Set as S
20+import Hakyll.Core.DirectedGraph.Internal
22+-- | Construction of directed graphs
25+ => [(a, Set a)] -- ^ List of (node, reachable neighbours)
26+ -> DirectedGraph a -- ^ Resulting directed graph
27+fromList = DirectedGraph . M.fromList . map (\(t, d) -> (t, Node t d))
29+-- | Get a set of reachable neighbours from a directed graph
32+ => a -- ^ Node to get the neighbours of
33+ -> DirectedGraph a -- ^ Graph to search in
34+ -> Set a -- ^ Set containing the neighbours
35+neighbours x = fromMaybe S.empty . fmap nodeNeighbours
36+ . M.lookup x . unDirectedGraph
38+-- | Reverse a directed graph (i.e. flip all edges)
43+reverse = mconcat . map reverse' . M.toList . unDirectedGraph
45+ reverse' (id', Node _ neighbours') = fromList $
46+ zip (S.toList neighbours') $ repeat $ S.singleton id'
48+-- | Filter a directed graph (i.e. remove nodes based on a predicate)
51+ => (a -> Bool) -- ^ Predicate
52+ -> DirectedGraph a -- ^ Graph
53+ -> DirectedGraph a -- ^ Resulting graph
55+ DirectedGraph . M.filterWithKey (\k _ -> predicate k) . unDirectedGraph
57+-- | Find all reachable nodes from a given node in the directed graph
59+reachableNodes :: Ord a => a -> DirectedGraph a -> Set a
60+reachableNodes x graph = reachable (neighbours x graph) (S.singleton x)
62+ reachable next visited
63+ | S.null next = visited
64+ | otherwise = reachable (sanitize neighbours') (next `S.union` visited)
66+ sanitize = S.filter (`S.notMember` visited)
67+ neighbours' = S.unions $ map (flip neighbours graph)
68+ $ S.toList $ sanitize next
71+exampleGraph :: DirectedGraph Int
72+exampleGraph = fromList
73+ [ makeNode 8 [2, 4, 6]
80+ makeNode tag deps = (tag, S.fromList deps)
82+cyclic :: DirectedGraph Int
84+ [ (1, S.fromList [2])
85+ , (2, S.fromList [1, 3])