{----------------------------------------------------------------------------- reactive-banana ------------------------------------------------------------------------------} module Reactive.Banana.Prim.Low.GraphTraversal ( GraphM , reversePostOrder1 , reversePostOrder ) where import Data.Hashable import qualified Data.HashSet as Set {----------------------------------------------------------------------------- Graph traversal ------------------------------------------------------------------------------} -- | Graph represented as map from a vertex to its direct successors. type GraphM m a = a -> m [a] -- | Computes the reverse post-order, -- listing all (transitive) successor of a node. -- -- Each vertex is listed *before* all its direct successors have been listed. reversePostOrder1 :: (Eq a, Hashable a, Monad m) => a -> GraphM m a -> m [a] reversePostOrder1 x = reversePostOrder [x] -- | Reverse post-order from multiple vertices. -- -- INVARIANT: For this to be a valid topological order, -- none of the vertices may have a direct predecessor. reversePostOrder :: (Eq a, Hashable a, Monad m) => [a] -> GraphM m a -> m [a] reversePostOrder xs successors = fst <$> go xs [] Set.empty where go [] rpo visited = return (rpo, visited) go (x:xs) rpo visited | x `Set.member` visited = go xs rpo visited | otherwise = do xs' <- successors x -- visit all direct successors (rpo', visited') <- go xs' rpo (Set.insert x visited) -- prepend this vertex as all direct successors have been visited go xs (x:rpo') visited'