{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE DeriveDataTypeable #-} -- | Graph defines the Graph class, which defines the basic things a -- graph must do. Peculiarities: -- (1) Graphs are directed with labelled nodes and -- arcs. These nodes and arcs have types. -- (2) The nodes and arcs are identified by values of type Node and Arc. -- These values are essentially strings. The strings are provided by -- the user; there is no mechanism for generating new unique strings. -- (This is because this is easy in the applications I have in mind.) -- (3) A necessary feature of these graphs is that it is supposed to -- be easy generate copies, both on the same system and on others. module Graphs.Graph( Graph(..), -- the Graph class -- Instances are parameterised on -- nodeLabel, nodeTypeLabel, arcLabel, arcTypeLabel. -- Nodes, Arc, NodeTypes, Arc Node, Arc, NodeType, ArcType, -- These are all instances of AtomString.StringClass (and so Read & Show). -- This means that they are essentially strings; the different types -- are just there to add a little abstraction. -- They are also all instances of Eq and Ord. However there -- is no guarantee that the ordering will be the same as for the -- corresponding strings. firstNode, -- :: Node -- first Node in the node ordering. -- They are also instances of Typeable. -- Updates Update(..), -- datatype encoding update to shared graph -- Like instances of Graph, parameterised on -- nodeLabel, nodeTypeLabel, arcLabel, arcTypeLabel. -- Derives Read and Show. CannedGraph(..), -- contains complete immutable contents of a Graph at some time -- Like instances of Graph, parameterised on -- nodeLabel, nodeTypeLabel, arcLabel, arcTypeLabel. -- Derives Read and Show. GraphConnection, GraphConnectionData(..), -- A GraphConnection contains the information generated by one -- instance of Graph, which can be used to construct another, -- including a CannedGraph. -- Like instances of Graph, parameterised on -- nodeLabel, nodeTypeLabel, arcLabel, arcTypeLabel. PartialShow(..), -- newtype alias for showing updates. -- NB. This type might get moved into ExtendedPrelude if it proves -- useful elsewhere. ) where import Util.AtomString import Util.QuickReadShow import Util.Dynamics import Graphs.NewNames class Graph graph where -- access functions getNodes :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> IO [Node] getArcs :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> IO [Arc] getNodeTypes :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> IO [NodeType] getArcTypes :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> IO [ArcType] getArcsOut :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> Node -> IO [Arc] getArcsIn :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> Node -> IO [Arc] getNodeLabel :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> Node -> IO nodeLabel getNodeType :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> Node -> IO NodeType getNodeTypeLabel :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> NodeType -> IO nodeTypeLabel getSource :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> Arc -> IO Node getTarget :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> Arc -> IO Node getArcLabel :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> Arc -> IO arcLabel getArcType :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> Arc -> IO ArcType getArcTypeLabel :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> ArcType -> IO arcTypeLabel shareGraph :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> GraphConnection nodeLabel nodeTypeLabel arcLabel arcTypeLabel newGraph :: GraphConnection nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> IO (graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel) -- Functions for changing the state. newNodeType :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> nodeTypeLabel -> IO NodeType newNode :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> NodeType -> nodeLabel -> IO Node newArcType :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> arcTypeLabel -> IO ArcType newArc :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> ArcType -> arcLabel -> Node -> Node -> IO Arc -- Other updates, such as deletions should be done with the update -- function. It is also possible to add nodes, arcs, arctypes and -- nodetypes using update; however in this case the caller is responsible -- for providing a globally new label. update :: graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> Update nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> IO () newEmptyGraph :: IO (graph nodeLabel nodeTypeLabel arcLabel arcTypeLabel) -- Actually newEmptyGraph can be synthesised from the above functions -- by synthesising a null GraphConnection and passing it to newGraph. ------------------------------------------------------------------------ -- GraphConnection ------------------------------------------------------------------------ type GraphConnection nodeLabel nodeTypeLabel arcLabel arcTypeLabel = (Update nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> IO ()) -> IO (GraphConnectionData nodeLabel nodeTypeLabel arcLabel arcTypeLabel) -- The first argument is passed back to the parent graph and -- indicates where to put changes to the parent graph since the -- canned graph was made. data GraphConnectionData nodeLabel nodeTypeLabel arcLabel arcTypeLabel = GraphConnectionData { graphState :: CannedGraph nodeLabel nodeTypeLabel arcLabel arcTypeLabel, -- current state of graph deRegister :: IO (), -- disables graphUpdates graphUpdate :: Update nodeLabel nodeTypeLabel arcLabel arcTypeLabel -> IO(), -- Similar to update (in class definition) except that -- it doesn't get echoed on graphUpdates. nameSourceBranch :: NameSourceBranch -- A source of new names. Each graph should contain a NameSource -- to generate new node strings. } ------------------------------------------------------------------------ -- Nodes, Arcs, NodeTypes, ArcTypes. ------------------------------------------------------------------------ newtype Node = Node AtomString deriving (Eq,Ord,Typeable) instance StringClass Node where toString (Node atomString) = toString atomString fromString atomString = Node (fromString atomString) instance Show Node where showsPrec = qShow instance Read Node where readsPrec = qRead firstNode :: Node firstNode = Node firstAtomString newtype NodeType = NodeType AtomString deriving (Eq,Ord,Typeable) instance StringClass NodeType where toString (NodeType atomString) = toString atomString fromString atomString = NodeType (fromString atomString) instance Show NodeType where showsPrec = qShow instance Read NodeType where readsPrec = qRead newtype Arc = Arc AtomString deriving (Eq,Ord,Typeable) instance StringClass Arc where toString (Arc atomString) = toString atomString fromString atomString = Arc (fromString atomString) instance Show Arc where showsPrec = qShow instance Read Arc where readsPrec = qRead newtype ArcType = ArcType AtomString deriving (Eq,Ord,Typeable) instance StringClass ArcType where toString (ArcType atomString) = toString atomString fromString atomString = ArcType (fromString atomString) instance Show ArcType where showsPrec = qShow instance Read ArcType where readsPrec = qRead ------------------------------------------------------------------------ -- Update ------------------------------------------------------------------------ data Update nodeLabel nodeTypeLabel arcLabel arcTypeLabel = -- NB. For various reasons, we decree that DeleteNode and DeleteArc should -- return normally, doing nothing, should the node already be deleted. NewNodeType NodeType nodeTypeLabel | SetNodeTypeLabel NodeType nodeTypeLabel | NewNode Node NodeType nodeLabel | DeleteNode Node | SetNodeLabel Node nodeLabel | SetNodeType Node NodeType | NewArcType ArcType arcTypeLabel | SetArcTypeLabel ArcType arcTypeLabel | NewArc Arc ArcType arcLabel Node Node | DeleteArc Arc | SetArcLabel Arc arcLabel | SetArcType Arc ArcType | MultiUpdate [Update nodeLabel nodeTypeLabel arcLabel arcTypeLabel] -- can be used to present unnecessary redrawing when making big -- updates. deriving (Read,Show) -- --------------------------------------------------------------------- -- Show instance which does not require argument types to be showable -- --------------------------------------------------------------------- newtype PartialShow a = PartialShow a instance Show (PartialShow a) => Show (PartialShow [a]) where show (PartialShow as) = show (map PartialShow as) instance Show (PartialShow ( Update nodeLabel nodeTypeLabel arcLabel arcTypeLabel)) where show (PartialShow update) = case update of NewNodeType nodeType nodeTypeLabel -> "NewNodeType " ++ show nodeType SetNodeTypeLabel nodeType nodeTypeLabel -> "SetNodeTypeLabel " ++ show nodeType NewNode node nodeType nodeLabel -> "NewNode " ++ show node ++ "::" ++ show nodeType DeleteNode node -> "DeleteNode " ++ show node SetNodeLabel node nodeLabel -> "SetNodeLabel " ++ show node SetNodeType node nodeType -> "SetNodeType " ++ show node ++ "::" ++ show nodeType NewArcType arcType arcTypeLabel -> "NewArcType " ++ show arcType SetArcTypeLabel arcType arcTypeLabel -> "SetArcTypeLabel " ++ show arcType NewArc arc arcType arcLabel node1 node2 -> "NewArc " ++ show arc ++ "::" ++ show arcType ++ " " ++ show node1 ++ "->" ++ show node2 DeleteArc arc -> "DeleteArc " ++ show arc SetArcLabel arc arcLabel -> "SetArcLabel " ++ show arc SetArcType arc arcType -> "SetArcType " ++ show arc ++ "::" ++ show arcType MultiUpdate updates -> "MultiUpdate " ++ show (PartialShow updates) instance Show (PartialShow ( CannedGraph nodeLabel nodeTypeLabel arcLabel arcTypeLabel)) where show (PartialShow (CannedGraph {updates = updates})) = "CannedGraph " ++ show (PartialShow updates) ------------------------------------------------------------------------ -- CannedGraph ------------------------------------------------------------------------ data CannedGraph nodeLabel nodeTypeLabel arcLabel arcTypeLabel = CannedGraph { updates :: [Update nodeLabel nodeTypeLabel arcLabel arcTypeLabel] -- This list may only contain NewNodeType, NewNode, NewArcType and -- NewArc definitions. The updates are processed in list order, so -- for example the endpoints of an Arc should be created before the Arc. } deriving (Read,Show)