(.module: [library [lux (#- Name) [abstract [equivalence (#+ Equivalence)] [monoid (#+ Monoid)] ["." monad (#+ do)]] [control ["." try (#+ Try)] ["." exception (#+ exception:)]] [data ["." text ["%" format (#+ format)]] [collection ["." dictionary (#+ Dictionary)] ["." set (#+ Set)] ["." list ("#\." mix)]]]]] ["." // #_ ["#" 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)))