(.module: [library [lux {"-" [Name]} [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)))