common/util/Util/Graph.hs (32 lines of code) (raw):
-- Copyright (c) Facebook, Inc. and its affiliates.
module Util.Graph
( postorder
) where
import Data.Hashable
import qualified Data.HashSet as HashSet
import qualified Data.HashMap.Strict as HashMap
-- | Post-order traversal of a graph: guarantees that the dependents
-- of a node occur before it in the result list, while as far as
-- possible retaining the original order of the nodes.
postorder
:: (Hashable vertex, Eq vertex)
=> [node]
-- ^ Nodes in the order of traversal
-> (node -> vertex)
-- ^ Extract a hashable vertex from the node
-> (node -> [vertex])
-- ^ Out-edges from a node. Vertices that aren't in the set of
-- nodes are ignored.
-> [node]
-- ^ Result of post-order traversal
postorder nodes vert out = go HashSet.empty nodes (\_ -> [])
where
m = HashMap.fromList [ (vert n, n) | n <- nodes ]
go seen [] cont = cont seen
go seen (n : nodes) cont
| v `HashSet.member` seen = go seen nodes cont
| otherwise = go (HashSet.insert v seen) deps
(\seen -> n : go seen nodes cont)
where
v = vert n
deps = [ n | v <- out n, Just n <- [HashMap.lookup v m] ]