2019-05-05 12:27:50 +02:00
|
|
|
{-# LANGUAGE NamedFieldPuns #-}
|
2019-05-06 08:21:04 +02:00
|
|
|
{-# LANGUAGE DeriveFunctor #-}
|
2019-05-05 12:27:50 +02:00
|
|
|
module Graph (
|
2019-05-06 08:21:04 +02:00
|
|
|
Graph(..)
|
2019-05-06 21:51:59 +02:00
|
|
|
, Vertex(..)
|
2019-05-06 08:21:04 +02:00
|
|
|
, editLabel
|
2019-05-06 16:47:29 +02:00
|
|
|
, follow
|
2019-05-06 08:21:04 +02:00
|
|
|
, open
|
|
|
|
, rewind
|
|
|
|
, singleton
|
|
|
|
, weave
|
2019-05-05 12:27:50 +02:00
|
|
|
) where
|
|
|
|
|
2019-05-06 16:47:29 +02:00
|
|
|
import Data.Map (Map)
|
|
|
|
import qualified Data.Map as Map (delete, empty, insert, lookup, toList)
|
2019-05-06 08:21:04 +02:00
|
|
|
import Tree (Tree(..), Structure(..))
|
2019-05-05 12:27:50 +02:00
|
|
|
|
2019-05-06 08:21:04 +02:00
|
|
|
data Vertex edge label = Vertex {
|
2019-05-05 12:27:50 +02:00
|
|
|
label :: label
|
2019-05-06 08:21:04 +02:00
|
|
|
, edges :: Map edge (Vertex edge label)
|
|
|
|
} deriving (Functor, Show)
|
2019-05-05 12:27:50 +02:00
|
|
|
|
2019-05-06 08:21:04 +02:00
|
|
|
instance Show edge => Tree (Vertex edge) where
|
|
|
|
getStructure (Vertex {label, edges}) = Node [
|
|
|
|
("(" ++ label ++ ")", Node $ recurseOnEdge <$> Map.toList edges)
|
|
|
|
]
|
|
|
|
where
|
|
|
|
recurseOnEdge (edge, vertex) = (show edge, getStructure vertex)
|
|
|
|
|
|
|
|
singleton :: label -> Vertex edge label
|
2019-05-05 12:27:50 +02:00
|
|
|
singleton label = Vertex {label, edges = Map.empty}
|
|
|
|
|
2019-05-06 08:21:04 +02:00
|
|
|
data Zipper edge label = Top | Zipper {
|
|
|
|
origin :: Zipper edge label
|
2019-05-05 12:27:50 +02:00
|
|
|
, from :: label
|
|
|
|
, by :: edge
|
2019-05-06 08:21:04 +02:00
|
|
|
, siblingEdges :: Map edge (Vertex edge label)
|
|
|
|
} deriving (Functor, Show)
|
|
|
|
|
|
|
|
data Graph edge label = Graph {
|
|
|
|
focus :: Vertex edge label
|
|
|
|
, context :: Zipper edge label
|
|
|
|
} deriving (Functor, Show)
|
2019-05-05 12:27:50 +02:00
|
|
|
|
2019-05-06 08:21:04 +02:00
|
|
|
instance (Ord edge, Show edge) => Tree (Graph edge) where
|
|
|
|
getStructure = getStructure . zipUp
|
2019-05-05 12:27:50 +02:00
|
|
|
|
2019-05-06 08:21:04 +02:00
|
|
|
open :: Vertex edge label -> Graph edge label
|
2019-05-05 12:27:50 +02:00
|
|
|
open focus = Graph {focus, context = Top}
|
|
|
|
|
2019-05-06 08:21:04 +02:00
|
|
|
zipUp :: Ord edge => Graph edge label -> Vertex edge label
|
2019-05-05 12:27:50 +02:00
|
|
|
zipUp graph =
|
|
|
|
case context graph of
|
|
|
|
Top -> focus graph
|
|
|
|
Zipper {origin, from, by, siblingEdges} -> zipUp $ Graph {
|
|
|
|
context = origin
|
|
|
|
, focus = Vertex {
|
|
|
|
label = from
|
|
|
|
, edges = Map.insert by (focus graph) siblingEdges
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-06 08:21:04 +02:00
|
|
|
rewind :: Ord edge => Graph edge label -> Graph edge label
|
2019-05-05 12:27:50 +02:00
|
|
|
rewind = open . zipUp
|
|
|
|
|
2019-05-06 08:21:04 +02:00
|
|
|
follow :: Ord edge => Graph edge label -> edge -> Maybe (Graph edge label)
|
2019-05-05 12:27:50 +02:00
|
|
|
follow (Graph {focus, context}) edge =
|
2019-05-06 16:47:29 +02:00
|
|
|
Map.lookup edge (edges focus) >>= \vertex -> Just $ Graph {
|
2019-05-05 12:27:50 +02:00
|
|
|
focus = vertex
|
|
|
|
, context = Zipper {
|
|
|
|
origin = context
|
|
|
|
, from = label $ focus
|
|
|
|
, by = edge
|
|
|
|
, siblingEdges = Map.delete edge $ edges focus
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-06 08:21:04 +02:00
|
|
|
weave :: (Monoid label, Ord edge) => Graph edge label -> [edge] -> Graph edge label
|
2019-05-05 12:27:50 +02:00
|
|
|
weave = foldl $ \graph edge ->
|
|
|
|
case graph `follow` edge of
|
|
|
|
Nothing -> Graph {
|
|
|
|
focus = singleton mempty
|
|
|
|
, context = Zipper {
|
|
|
|
origin = context graph
|
|
|
|
, from = label $ focus graph
|
|
|
|
, by = edge
|
|
|
|
, siblingEdges = edges $ focus graph
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Just newGraph -> newGraph
|
|
|
|
|
2019-05-06 08:21:04 +02:00
|
|
|
editLabel :: Graph edge label -> (label -> label) -> Graph edge label
|
|
|
|
editLabel graph@(Graph {focus}) labelEditor =
|
|
|
|
graph {focus = focus {label = labelEditor $ label focus}}
|