... This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. ... If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. (.require [library [lux (.except nat) [abstract [equivalence (.only Equivalence)] [order (.only Order)] [monoid (.only Monoid)] [codec (.only Codec)] [monad (.only do)]] [control ["<>" parser] ["[0]" function] ["[0]" maybe] ["[0]" try]] [data ["[0]" product] ["[0]" text (.use "[1]#[0]" monoid)]] [meta ["[0]" code (.only) ["<[1]>" \\parser (.only Parser)]] [macro [syntax (.only syntax)]]]]] [// ["n" nat (.use "[1]#[0]" decimal)] [// [arithmetic (.only Arithmetic)]]]) (type .public Ratio (Record [#numerator Nat #denominator Nat])) (def .public (nat value) (-> Ratio (Maybe Nat)) (when (the #denominator value) 1 {.#Some (the #numerator value)} _ {.#None})) (def .public (normal (open "/[0]")) (-> Ratio Ratio) (let [common (n.gcd /#numerator /#denominator)] [..#numerator (n./ common /#numerator) ..#denominator (n./ common /#denominator)])) (def .public ratio (syntax (_ [numerator .any ?denominator (<>.maybe .any)]) (in (list (` (normal [..#numerator (, numerator) ..#denominator (, (maybe.else (' 1) ?denominator))])))))) (def .public (= parameter subject) (-> Ratio Ratio Bit) (n.= (n.* (the #numerator parameter) (the #denominator subject)) (n.* (the #denominator parameter) (the #numerator subject)))) (def .public equivalence (Equivalence Ratio) (implementation (def = ..=))) (def (equalized parameter subject) (-> Ratio Ratio [Nat Nat]) [(n.* (the #denominator subject) (the #numerator parameter)) (n.* (the #denominator parameter) (the #numerator subject))]) (def .public (< parameter subject) (-> Ratio Ratio Bit) (let [[parameter' subject'] (..equalized parameter subject)] (n.< parameter' subject'))) (def .public (<= parameter subject) (-> Ratio Ratio Bit) (or (< parameter subject) (= parameter subject))) (def .public (> parameter subject) (-> Ratio Ratio Bit) (..< subject parameter)) (def .public (>= parameter subject) (-> Ratio Ratio Bit) (or (> parameter subject) (= parameter subject))) (def .public order (Order Ratio) (implementation (def equivalence ..equivalence) (def < ..<))) (def .public (+ parameter subject) (-> Ratio Ratio Ratio) (let [[parameter' subject'] (..equalized parameter subject)] (normal [(n.+ parameter' subject') (n.* (the #denominator parameter) (the #denominator subject))]))) (def .public (- parameter subject) (-> Ratio Ratio Ratio) (let [[parameter' subject'] (..equalized parameter subject)] (normal [(n.- parameter' subject') (n.* (the #denominator parameter) (the #denominator subject))]))) (def .public (* parameter subject) (-> Ratio Ratio Ratio) (normal [(n.* (the #numerator parameter) (the #numerator subject)) (n.* (the #denominator parameter) (the #denominator subject))])) (def .public (/ parameter subject) (-> Ratio Ratio Ratio) (let [[parameter' subject'] (..equalized parameter subject)] (normal [subject' parameter']))) (def .public (% parameter subject) (-> Ratio Ratio Ratio) (let [[parameter' subject'] (..equalized parameter subject) quot (n./ parameter' subject')] (..- (revised #numerator (n.* quot) parameter) subject))) (def .public arithmetic (Arithmetic Ratio) (implementation (def + ..+) (def - ..-) (def * ..*) (def / ../))) (def .public (reciprocal (open "/[0]")) (-> Ratio Ratio) [..#numerator /#denominator ..#denominator /#numerator]) (def separator ":") (def .public codec (Codec Text Ratio) (implementation (def (encoded (open "/[0]")) (all text#composite (n#encoded /#numerator) ..separator (n#encoded /#denominator))) (def (decoded input) (when (text.split_by ..separator input) {.#Some [num denom]} (do try.monad [numerator (n#decoded num) denominator (n#decoded denom)] (in (normal [#numerator numerator #denominator denominator]))) {.#None} {.#Left (text#composite "Invalid syntax for ratio: " input)})))) (with_template [ ] [(def .public (Monoid Ratio) (implementation (def identity (..ratio )) (def composite )))] [0 ..+ addition] [1 ..* multiplication] )