aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/library/lux/math/number/ratio.lux
blob: c4fe7a26d92324c2f7ddbdcff90afe8f2323fcca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
(.using
 [library
  [lux (.except nat)
   [abstract
    [equivalence (.only Equivalence)]
    [order (.only Order)]
    [monoid (.only Monoid)]
    [codec (.only Codec)]
    [monad (.only do)]]
   [control
    ["[0]" function]
    ["[0]" maybe]
    ["[0]" try]
    ["<>" parser (.only)
     ["<[0]>" code (.only Parser)]]]
   [data
    ["[0]" product]
    ["[0]" text (.open: "[1]#[0]" monoid)]]
   [macro
    [syntax (.only syntax)]
    ["[0]" code]]]]
 [//
  ["n" nat (.open: "[1]#[0]" decimal)]])

(type: .public Ratio
  (Record
   [#numerator Nat
    #denominator Nat]))

(def .public (nat value)
  (-> Ratio (Maybe Nat))
  (case (the #denominator value)
    1 {.#Some (the #numerator value)}
    _ {.#None}))

(def (normal (open "_[0]"))
  (-> Ratio Ratio)
  (let [common (n.gcd _#numerator _#denominator)]
    [..#numerator (n./ common _#numerator)
     ..#denominator (n./ common _#denominator)]))

(def .public ratio
  (syntax (_ [numerator <code>.any
              ?denominator (<>.maybe <code>.any)])
    (in (list (` ((~! ..normal) [..#numerator (~ numerator)
                                 ..#denominator (~ (maybe.else (' 1) ?denominator))]))))))

(def .public (= parameter subject)
  (-> Ratio Ratio Bit)
  (and (n.= (the #numerator parameter)
            (the #numerator subject))
       (n.= (the #denominator parameter)
            (the #denominator 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 (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)
     (case (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 [<identity> <composite> <name>]
  [(def .public <name>
     (Monoid Ratio)
     (implementation
      (def identity (..ratio <identity>))
      (def composite <composite>)))]
  
  [0 ..+ addition]
  [1 ..* multiplication]
  )