{
: G make
}

Where

Define (make MAP)
    Let compare MAP.compare
    Let SET (SEARCH.SET MAP.compare)
    In
    Define (traverse g adj i stack preorder assigned components)
        Unfold {adj i stack preorder assigned components}
            Let {v neighbors} adj
            In
            Let preorder (MAP.insert preorder {v i})
            Let stack [v & stack]
            In
            Let {link j stack preorder assigned components}
                (LIST.reduce neighbors
                    {i [i + 1] stack preorder assigned components}
                    Func {state w}
                        Let {link i stack preorder assigned components} state
                        In
                        Match (SET.search assigned w)
                        | 'just._ state
                        | 'nothing
                            Match (MAP.search preorder w)
                            | 'just.{_ j}
                                Let link (Z.min link j)
                                In
                                {link i stack preorder assigned components}
                            | 'nothing
                                Let adj
                                    Match (MAP.search g w)
                                    | 'nothing {w 'nil}
                                    | 'just.adj adj
                                    ;
                                In
                                Let {link_rec i stack preorder assigned components}
                                    (Fold adj i stack preorder assigned components)
                                In
                                Let link (Z.min link link_rec)
                                In
                                {link i stack preorder assigned components}
                            ;
                        ;)
            In
            If [i = link]
                Block
                    Let {c stack assigned}
                        Iterate {c stack assigned} From {'nil stack assigned}
                            Match stack
                            | 'cons.{w stack}
                                Let assigned (SET.insert assigned w)
                                In
                                Match (compare w v)
                                | 'equal {[v & c] stack assigned}
                                | _ (Continue [w & c] stack assigned)
                                ;
                            ;
                    In
                    {link j stack preorder assigned [c & components]}
                {link j stack preorder assigned components}
    In
    Define (strongly_connected_components g)
        Iterate {adjs i stack preorder assigned components}
        From {(MAP.list g) 0 'nil MAP.empty SET.empty 'nil}
            Match adjs
            | 'nil (LIST.reverse components)
            | 'cons.{adj adjs}
                Let {v _} adj
                In
                Match (SET.search assigned v)
                | 'just._
                    (Continue adjs i stack preorder assigned components)
                | 'nothing
                    Let {link i stack preorder assigned components}
                        (traverse g adj i stack preorder assigned components)
                    In
                    (Continue adjs i stack preorder assigned components)
                ;
            ;
    In
    Define (layers g)
        Iterate {layers adjs} From {'nil (MAP.list g)}
            Let {layer adjs}
                (LIST.fold adjs {'nil 'nil}
                    Func {{v neighbors} {layer adjs}}
                        Match neighbors
                        | 'nil {[v & layer] adjs}
                        | 'cons._ {layer [{v neighbors} & adjs]}
                        ;)
            In
            Match layer
            | 'nil layers
            | 'cons._
                Let removed (LIST.reduce layer SET.empty SET.insert)
                In
                Let adjs
                    (LIST.map adjs
                        Func {v neighbors}
                            Let neighbors
                                (SET.list
                                    (SET.diff (SET.new neighbors) removed))
                            In
                            {v neighbors})
                In
                (Continue [layer & layers] adjs)
            ;
    In
    {
    : strongly_connected_components
    : layers
    }

Where

Let die OS.die

Where

Let LIST Package "list"
Let OS Package "os"
Let SEARCH Package "search"
Let STDIO Package "stdio"
Let Z Package "z"