summaryrefslogtreecommitdiff
path: root/src/Hakyll/Core/DirectedGraph.hs
blob: bc2a2340bb2dc3b1e833ff02f0d3041e41d149a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
--------------------------------------------------------------------------------
-- | Representation of a directed graph. In Hakyll, this is used for dependency
-- tracking.
{-# LANGUAGE DeriveDataTypeable         #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Hakyll.Core.DirectedGraph
    ( DirectedGraph

    , fromList
    , toList

    , member
    , nodes
    , neighbours
    ) where


--------------------------------------------------------------------------------
import           Control.Arrow   (second)
import           Control.DeepSeq (NFData)
import           Data.Binary     (Binary)
import           Data.Map        (Map)
import qualified Data.Map        as M
import           Data.Maybe      (fromMaybe)
import           Data.Monoid     (Monoid (..))
import           Data.Set        (Set)
import qualified Data.Set        as S
import           Data.Typeable   (Typeable)
import           Prelude         hiding (reverse)


--------------------------------------------------------------------------------
-- | Type used to represent a directed graph
newtype DirectedGraph a = DirectedGraph {unDirectedGraph :: Map a [a]}
    deriving (Show, Binary, NFData, Typeable)


--------------------------------------------------------------------------------
-- | Allow users to concatenate different graphs
instance Ord a => Monoid (DirectedGraph a) where
    mempty                                        = DirectedGraph M.empty
    mappend (DirectedGraph m1) (DirectedGraph m2) = DirectedGraph $
        M.unionWith (\x y -> sortUnique (x ++ y)) m1 m2


--------------------------------------------------------------------------------
-- | Construction of directed graphs
fromList :: Ord a
         => [(a, [a])]       -- ^ List of (node, reachable neighbours)
         -> DirectedGraph a  -- ^ Resulting directed graph
fromList = DirectedGraph . M.fromList . map (second sortUnique)


--------------------------------------------------------------------------------
-- | Deconstruction of directed graphs
toList :: DirectedGraph a
       -> [(a, [a])]
toList = M.toList . unDirectedGraph


--------------------------------------------------------------------------------
-- | Check if a node lies in the given graph
member :: Ord a
       => a                -- ^ Node to check for
       -> DirectedGraph a  -- ^ Directed graph to check in
       -> Bool             -- ^ If the node lies in the graph
member n = M.member n . unDirectedGraph


--------------------------------------------------------------------------------
-- | Get all nodes in the graph
nodes :: Ord a
      => DirectedGraph a  -- ^ Graph to get the nodes from
      -> Set a            -- ^ All nodes in the graph
nodes = M.keysSet . unDirectedGraph


--------------------------------------------------------------------------------
-- | Get a set of reachable neighbours from a directed graph
neighbours :: Ord a
           => a                -- ^ Node to get the neighbours of
           -> DirectedGraph a  -- ^ Graph to search in
           -> [a]              -- ^ Set containing the neighbours
neighbours x dg = fromMaybe [] $ M.lookup x $ unDirectedGraph dg


--------------------------------------------------------------------------------
-- | Sort and make unique
sortUnique :: Ord a => [a] -> [a]
sortUnique = S.toAscList . S.fromList