(.require [library [lux (.except) [abstract ["[0]" equivalence (.only Equivalence)]] [data ["[0]" product] ["[0]" text (.only) ["%" \\format]]] [math [number ["n" nat]]] [meta ["[0]" static] [type ["[0]" nominal]]]]] [/ ["/" currency]]) (nominal.def .public (Money currency) (Record [#currency (/.Currency currency) #amount Nat]) (def .public (money currency amount) (All (_ currency) (-> (/.Currency currency) Nat (Money currency))) (nominal.abstraction [#currency currency #amount amount])) (with_template [ ] [(def .public (All (_ currency) (-> (Money currency) )) (|>> nominal.representation (the )))] [currency #currency (/.Currency currency)] [amount #amount Nat] ) (def .public equivalence (All (_ of) (Equivalence (Money of))) (at equivalence.functor each (|>> nominal.representation) (all product.equivalence /.equivalence n.equivalence ))) (def .public (+ parameter subject) (All (_ currency) (-> (Money currency) (Money currency) (Money currency))) (|> subject nominal.representation (revised #amount (n.+ (|> parameter nominal.representation (the #amount)))) nominal.abstraction)) (def .public (- parameter subject) (All (_ currency) (-> (Money currency) (Money currency) (Maybe (Money currency)))) (let [parameter (nominal.representation parameter) subject (nominal.representation subject)] (if (n.< (the #amount parameter) (the #amount subject)) {.#None} {.#Some (nominal.abstraction [#currency (the #currency subject) #amount (n.- (the #amount parameter) (the #amount subject))])}))) (def .public (format it) (All (_ currency) (%.Format (Money currency))) (let [[currency amount] (nominal.representation it) [macro micro] (n./% (/.subdivisions currency) amount)] (%.format (%.nat macro) (when micro 0 "" _ (%.format "." (%.nat micro))) " " (/.alphabetic_code currency)))) )