(.module: [lux (#- Name) [abstract [equivalence (#+ Equivalence)] [monoid (#+ Monoid)] ["." monad (#+ do)]] [control ["." try (#+ Try)] ["." exception (#+ exception:)]] [data ["." text ["%" format (#+ format)]] [collection ["." dictionary (#+ Dictionary)] ["." set (#+ Set)] ["." list ("#@." fold)]]]] ["." // #_ ["#" profile (#+ Name Profile)]]) (type: #export Project (Dictionary Name Profile)) (def: #export (project name profile) (-> Name Profile Project) (dictionary.from-list text.hash (list [name profile]))) (def: #export equivalence (Equivalence Project) (dictionary.equivalence //.equivalence)) (structure: #export monoid (Monoid Project) (def: identity (dictionary.new text.hash)) (def: compose (dictionary.merge-with (:: //.monoid compose)))) (exception: #export (unknown-profile {name Name}) (exception.report ["Name" (%.text name)])) (exception: #export (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.get name project) (#.Some profile) (case (list.find (set.member? lineage) (get@ #//.parents profile)) (#.Some ouroboros) (exception.throw ..circular-dependency [ouroboros name]) #.None (do {@ try.monad} [parents (monad.map @ (profile' (set.add name lineage) project) (get@ #//.parents profile))] (wrap (list@fold (function (_ parent child) (:: //.monoid compose child parent)) (set@ #//.parents (list) profile) parents)))) #.None (exception.throw ..unknown-profile [name]))) (def: #export (profile name project) (-> Name Project (Try Profile)) (..profile' (set.new text.hash) project name))