(.require [library [lux (.except) [abstract [equivalence (.only Equivalence)] [monoid (.only Monoid)] ["[0]" monad (.only do)]] [control ["[0]" try (.only Try)] ["[0]" exception (.only Exception)]] [data ["[0]" text (.only) ["%" \\format (.only format)]] [collection ["[0]" dictionary (.only Dictionary)] ["[0]" set (.only Set)] ["[0]" list (.use "[1]#[0]" mix)]]]]] ["[0]" // ["[1]" profile (.only 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)) (def .public monoid (Monoid Project) (implementation (def identity (dictionary.empty text.hash)) (def composite (dictionary.composite_with (of //.monoid composite))))) (exception.def .public (unknown_profile name) (Exception Name) (exception.report (list ["Name" (%.text name)]))) (exception.def .public (circular_dependency [dependee dependent]) (Exception [Name Name]) (exception.report (list ["Dependent" (%.text dependent)] ["Dependee" (%.text dependee)]))) (def (profile' lineage project name) (-> (Set Name) Project Name (Try Profile)) (when (dictionary.value name project) {.#Some profile} (when (list.example (set.member? lineage) (the //.#parents profile)) {.#Some ouroboros} (exception.except ..circular_dependency [ouroboros name]) {.#None} (do [! try.monad] [parents (monad.each ! (profile' (set.has name lineage) project) (the //.#parents profile))] (in (list#mix (function (_ parent child) (of //.monoid composite child parent)) (has //.#parents (list) profile) parents)))) {.#None} (exception.except ..unknown_profile [name]))) (def .public profile (-> Project Name (Try Profile)) (..profile' (set.empty text.hash)))