(.module: [lux (#- Name) [abstract ["." monad (#+ do)] ["." equivalence (#+ Equivalence)]] [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 empty (dictionary.from-list text.hash (list [//.default (:: //.monoid identity)]))) (def: #export equivalence (Equivalence Project) (dictionary.equivalence //.equivalence)) (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)) profile parents)))) #.None (exception.throw ..unknown-profile [name]))) (def: #export (profile project name) (-> Project Name (Try Profile)) (profile' (set.new text.hash) project name))