File ‹topo_sort.ML›
signature TOPO_SORT =
sig
val topo_sort : {cmp: 'a * 'a -> order, graph : 'a -> 'a list,
converse : 'a -> 'a list} ->
'a list ->
'a list list
end
structure Topo_Sort : TOPO_SORT =
struct
fun dfs_finishes (cmp, neighbours) nodes = let
datatype 'a action = Visit of 'a | Finish of 'a
fun recurse visited result actlist =
case actlist of
[] => result
| Visit n :: rest => if Binaryset.member(visited, n) then
recurse visited result rest
else let
val ns = map Visit (neighbours n)
in
recurse (Binaryset.add(visited, n))
result
(ns @ (Finish n :: rest))
end
| Finish n :: rest => recurse visited (n::result) rest
in
recurse (Binaryset.empty cmp) [] (map Visit nodes)
end
fun fcons _ [] = raise Fail "Should never happen"
| fcons x (h::t) = (x::h) :: t
fun dfs_trees (cmp, neighbours) nodes = let
datatype 'a action = Visit of 'a | Initial of 'a
fun recurse visited result actlist =
case actlist of
[] => result
| Initial n :: rest => if Binaryset.member(visited,n) then
recurse visited result rest
else
recurse (Binaryset.add(visited, n))
([n] :: result)
(map Visit (neighbours n) @ rest)
| Visit n :: rest => if Binaryset.member(visited, n) then
recurse visited result rest
else
recurse (Binaryset.add(visited, n))
(fcons n result)
(map Visit (neighbours n) @ rest)
in
recurse (Binaryset.empty cmp) [] (map Initial nodes)
end
fun topo_sort {cmp, graph, converse} nodes =
dfs_trees (cmp, converse) (dfs_finishes (cmp, graph) nodes)
end;