{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TupleSections #-}
module DepTrack (
DepTrackT
, track
, declare
, ToDep (..)
, dep
, evalDeps
, value
, evalDepForest
, evalDepGraph
, evalDepForest1
, GraphData
, evalDepGraph1
, buildGraph
, inject
) where
import Control.Applicative (liftA)
import Control.Monad.Writer.Strict (WriterT, writer, tell, runWriterT)
import Data.DList (DList)
import qualified Data.DList as DList
import Data.Graph (Graph, Vertex)
import qualified Data.Graph as Graph
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Monoid ((<>))
import Data.Set (Set)
import qualified Data.Set as Set
import Data.Tree (Forest, Tree (..))
import qualified Data.Tree as Tree
import qualified Text.Parsec as Parsec
import DepTrack.DepCrumb
import DepTrack.Parsing
type DepTrackT a m = WriterT (DList (DepCrumb a)) m
declare :: (Monad m) => a -> DepTrackT a m b -> DepTrackT a m b
declare obj = track (const obj)
track :: (Monad m) => (b -> a) -> DepTrackT a m b -> DepTrackT a m b
track f op = do
push
a <- op
_ <- pop (f a)
return a
where
push :: (Monad m) => DepTrackT a m ()
push = tell (DList.singleton Push)
pop :: (Monad m) => a -> DepTrackT a m a
pop a = writer (a, DList.singleton (Pop a))
inject :: (Monad m) => DepTrackT a m b -> DepTrackT a m c -> DepTrackT a m (b, c)
inject m1 m2 = do
spadeIn
a <- m1
spadeMiddle
b <- m2
spadeOut
return (a,b)
where
spadeIn :: (Monad m) => DepTrackT a m ()
spadeIn = tell (DList.singleton SpadeIn)
spadeMiddle :: (Monad m) => DepTrackT a m ()
spadeMiddle = tell (DList.singleton SpadeMiddle)
spadeOut :: (Monad m) => DepTrackT a m ()
spadeOut = tell (DList.singleton SpadeOut)
forestToPairs :: Forest a -> [(a,[a])]
forestToPairs = concatMap treeToPairs
treeToPairs :: Tree a -> [(a,[a])]
treeToPairs (Node x ts) = directDeps : childrenDeps
where
directDeps = (x, fmap Tree.rootLabel ts)
childrenDeps = forestToPairs ts
mapGraphFromForest :: Ord k => (a -> k) -> Forest a -> Map k (a, Set k)
mapGraphFromForest fKey ts = Map.fromListWithKey f (formatPairs ts)
where
f _ (a,xs) (_,ys) = (a, xs <> ys)
formatPairs = fmap (\(x,ys) -> (fKey x, (x, Set.fromList (fmap fKey ys)))) . forestToPairs
graphFromMap :: Ord k => Map k (a, Set k) -> GraphData a k
graphFromMap = Graph.graphFromEdges . fmap formatPair . Map.toList
where
formatPair (k, (a, ks)) = (a, k, Set.toList ks)
buildGraph :: Ord k => (a -> k) -> Forest a -> GraphData a k
buildGraph f ts = graphFromMap $ mapGraphFromForest f ts
value :: (Monad m) => DepTrackT a m b -> m b
value = fmap fst . runWriterT
evalDeps :: DepTrackT a m b -> m (b, DList (DepCrumb a))
evalDeps = runWriterT
evalDepForest :: (Monad m, Show a) =>
DepTrackT a m b -> m (b, Either Parsec.ParseError (Forest a))
evalDepForest = (fmap . fmap) f . evalDeps
where
f crumbs = let crumbs' = DList.toList crumbs
in Parsec.parse dependencies "" crumbs'
evalDepForest1 :: (Monad m, Show a) =>
DepTrackT a m b -> m (b, Forest a)
evalDepForest1 = liftA (fmap (fromRight "deptrack is broken")) . evalDepForest
fromRight :: String -> Either a b -> b
fromRight _ (Right x) = x
fromRight msg (Left _) = error msg
type GraphData a k = ( Graph
, Vertex -> (a, k, [k])
, k -> Maybe Vertex
)
evalDepGraph :: (Monad m, Ord k, Show a) =>
DepTrackT a m b
-> (a -> k)
-> m (b, Either Parsec.ParseError (GraphData a k))
evalDepGraph x fKey = (fmap . fmap . fmap) (buildGraph fKey) (evalDepForest x)
evalDepGraph1 :: (Monad m, Ord k, Show a) =>
DepTrackT a m b -> (a -> k) -> m (b, GraphData a k)
evalDepGraph1 x fKey = liftA (fmap (fromRight "deptrack is broken")) $ evalDepGraph x fKey
class ToDep a b where
toDep :: a -> b
dep :: (ToDep a b, Monad m) =>
DepTrackT b m a -> DepTrackT b m a
dep = track toDep