{Record G:make}

Where

Let (make MAP)
    Let compare MAP.compare
    In
    Let ADJ
        {Record
            vertex:Func item. item.0
            neighbors:Func item. item.1}
    Let SET (SEARCH.SET compare)
    In
    Let (min a b) If (a < b) a b
    In
    Define (traverse g adj i stack preorder assigned components)
        Let v (ADJ.vertex adj)
        Let neighbors (ADJ.neighbors adj)
        In
        Let preorder (MAP.insert preorder {v i})
        Let stack (v :: stack)
        In
        Let {link i' 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 (min link j)
                            In
                            {link i stack preorder assigned components}
                        | `nothing
                            Let adj
                                Match (MAP.search g w)
                                | `nothing {w []}
                                | `just.adj adj
                                ;
                            In
                            Let {link' i stack preorder assigned components}
                                (traverse g adj i stack preorder assigned
                                    components)
                            In
                            Let link (min link link')
                            In
                            {link i stack preorder assigned components}
                        ;
                    ;)
        In
        If (i = link)
            Block
                Let {c stack assigned}
                    Iterate {c stack assigned} From {[] 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 i' stack preorder assigned (c :: components)}
            {link i' stack preorder assigned components}
    In
    Let (strongly_connected_components g)
        Iterate {g adjs i stack preorder assigned components}
        From {g (MAP.list g) 0 [] MAP.empty SET.empty []}
            Match adjs
            | `nil (LIST.reverse components)
            | `cons.{adj adjs}
                Match (SET.search assigned (ADJ.vertex adj))
                | `just._
                    Continue {g adjs i stack preorder assigned components}
                | `nothing
                    Let {link i stack preorder assigned components}
                        (traverse g adj i stack preorder assigned components)
                    In
                    Continue {g adjs i stack preorder assigned components}
                ;
            ;
    In
    Let (layers g)
        Iterate {layers adjs} From {[] (MAP.list g)}
            Let {layer adjs}
                (LIST.fold adjs {[] []}
                    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
    {Record 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"