\begin{code}
{-# OPTIONS --safe  --termination-depth=2 #-}
open import Prelude

module TopoSort {A : Type a} (disc : Discrete A) where

open import Data.Set.Noetherian disc
open import Data.Set.Discrete disc
open import Data.Set
open import Data.RoseTree

GraphOf : Type a  Type a
GraphOf A = A  List A
\end{code}
%<*trace-ty>
\begin{code}
trace : GraphOf A  List A  Forest A
\end{code}
%</trace-ty>
\begin{code}
trace g dom = expand dom  (noeth Dom)
  where
  Dom : 𝒦 A
  Dom = 𝒦-fromList dom

  expand : List A   seen  NoethAcc Dom seen  List (Tree A)
  expand []        seen na = []
  expand (v  vs)  seen (nacc wf) with v ∈? Dom | v ∈? seen
  ... | yes v∈Dom | no v∉seen =
    (v & expand (g v) (v  seen) (wf v v∈Dom v∉seen))  expand vs seen (nacc wf)
  ... | _ | _ = expand vs seen (nacc wf)
\end{code}
%<*topo-sort>
\begin{code}
topo-sort  :  GraphOf A
             List A  List A
topo-sort g = fst  sort-f ([] , )  trace g
  where mutual
  sort-f :  List A × 𝒦 A  Forest A 
            List A × 𝒦 A
  sort-f ac []        = ac
  sort-f ac (n  ns)  = sort-t n (sort-f ac ns)

  sort-t : Tree A   List A × 𝒦 A
                    List A × 𝒦 A
  sort-t (v & cs) (sorted , seen) =
    if does (v ∈? seen)
      then  (sorted , seen)
      else  map₁ (v ∷_)
            (sort-f (sorted , v  seen) cs)
\end{code}
%</topo-sort>