(.using [library [lux "*" [abstract [equivalence {"+" Equivalence}] [monoid {"+" Monoid}] ["[0]" monad {"+" do}]] [control ["[0]" try {"+" Try}] ["[0]" exception {"+" exception:}]] [data ["[0]" text ["%" format {"+" format}]] [collection ["[0]" dictionary {"+" Dictionary}] ["[0]" set {"+" Set}] ["[0]" list ("[1]#[0]" mix)]]]]] ["[0]" // "_" ["[1]" profile {"+" Name Profile}]]) (def: .public file "project.lux") (type: .public Project (Dictionary Name Profile)) (def: .public (project name profile) (-> Name Profile Project) (dictionary.of_list text.hash (list [name profile]))) (def: .public equivalence (Equivalence Project) (dictionary.equivalence //.equivalence)) (implementation: .public monoid (Monoid Project) (def: identity (dictionary.empty text.hash)) (def: composite (dictionary.merged_with (# //.monoid composite)))) (exception: .public (unknown_profile [name Name]) (exception.report ["Name" (%.text name)])) (exception: .public (circular_dependency [dependee Name dependent Name]) (exception.report ["Dependent" (%.text dependent)] ["Dependee" (%.text dependee)])) (def: (profile' lineage project name) (-> (Set Name) Project Name (Try Profile)) (case (dictionary.value name project) {.#Some profile} (case (list.example (set.member? lineage) (value@ //.#parents profile)) {.#Some ouroboros} (exception.except ..circular_dependency [ouroboros name]) {.#None} (do [! try.monad] [parents (monad.each ! (profile' (set.has name lineage) project) (value@ //.#parents profile))] (in (list#mix (function (_ parent child) (# //.monoid composite child parent)) (with@ //.#parents (list) profile) parents)))) {.#None} (exception.except ..unknown_profile [name]))) (def: .public profile (-> Project Name (Try Profile)) (..profile' (set.empty text.hash)))