(.module: [library [lux {"-" [Module]} [abstract ["." monad {"+" [do]}]] [control ["." maybe ("#\." functor)] ["." try {"+" [Try]}] ["." state] ["." function ["." memo {"+" [Memo]}]]] [data ["." text ["%" format {"+" [format]}]] [collection ["." list ("#\." functor mix)] ["." dictionary {"+" [Dictionary]}] ["." set {"+" [Set]}]]]]] [/// ["." archive {"+" [Output Archive]} [key {"+" [Key]}] ["." descriptor {"+" [Module Descriptor]}] ["." document {"+" [Document]}]]]) (type: Ancestry (Set Module)) (def: fresh Ancestry (set.empty text.hash)) (type: .public Graph (Dictionary Module Ancestry)) (def: empty Graph (dictionary.empty text.hash)) (def: .public modules (-> Graph (List Module)) dictionary.keys) (type: Dependency (Record [#module Module #imports Ancestry])) (def: .public graph (-> (List Dependency) Graph) (list\mix (function (_ [module imports] graph) (dictionary.has module imports graph)) ..empty)) (def: (ancestry archive) (-> Archive Graph) (let [memo (: (Memo Module Ancestry) (function (_ recur module) (do {! state.monad} [.let [parents (case (archive.find module archive) (#try.Success [descriptor document]) (value@ #descriptor.references descriptor) (#try.Failure error) ..fresh)] ancestors (monad.each ! recur (set.list parents))] (in (list\mix set.union parents ancestors))))) ancestry (memo.open memo)] (list\mix (function (_ module memory) (if (dictionary.key? memory module) memory (let [[memory _] (ancestry [memory module])] memory))) ..empty (archive.archived archive)))) (def: (dependency? ancestry target source) (-> Graph Module Module Bit) (let [target_ancestry (|> ancestry (dictionary.value target) (maybe.else ..fresh))] (set.member? target_ancestry source))) (type: .public Order (List [Module [archive.ID [Descriptor (Document .Module) Output]]])) (def: .public (load_order key archive) (-> (Key .Module) Archive (Try Order)) (let [ancestry (..ancestry archive)] (|> ancestry dictionary.keys (list.sorted (..dependency? ancestry)) (monad.each try.monad (function (_ module) (do try.monad [module_id (archive.id module archive) [descriptor document output] (archive.find module archive) document (document.check key document)] (in [module [module_id [descriptor document output]]])))))))