-
Notifications
You must be signed in to change notification settings - Fork 92
Expand file tree
/
Copy pathOrd.purs
More file actions
264 lines (228 loc) · 6.51 KB
/
Copy pathOrd.purs
File metadata and controls
264 lines (228 loc) · 6.51 KB
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
module Data.Ord
( class Ord
, compare
, class Ord1
, compare1
, lessThan
, (<)
, lessThanOrEq
, (<=)
, greaterThan
, (>)
, greaterThanOrEq
, (>=)
, comparing
, min
, max
, clamp
, between
, abs
, signum
, module Data.Ordering
, class OrdRecord
, compareRecord
) where
import Data.Eq (class Eq, class Eq1, class EqRecord, (/=))
import Data.Symbol (class IsSymbol, reflectSymbol)
import Data.Ordering (Ordering(..))
import Data.Ring (class Ring, zero, one, negate)
import Data.Unit (Unit)
import Data.Void (Void)
import Prim.Row as Row
import Prim.RowList as RL
import Record.Unsafe (unsafeGet)
import Type.Proxy (Proxy(..))
-- | The `Ord` type class represents types which support comparisons with a
-- | _total order_.
-- |
-- | `Ord` instances should satisfy the laws of total orderings:
-- |
-- | - Reflexivity: if `a == b` then `a <= b`
-- | - Antisymmetry: if `a <= b` and `b <= a` then `a == b`
-- | - Transitivity: if `a <= b` and `b <= c` then `a <= c`
-- |
-- | **Note:** The `Number` type is not an entirely law abiding member of this
-- | class due to the presence of `NaN`, since `NaN <= NaN` evaluates to `false`
class Eq a <= Ord a where
compare :: a -> a -> Ordering
instance ordBoolean :: Ord Boolean where
compare = ordBooleanImpl LT EQ GT
instance ordInt :: Ord Int where
compare = ordIntImpl LT EQ GT
instance ordNumber :: Ord Number where
compare = ordNumberImpl LT EQ GT
instance ordString :: Ord String where
compare = ordStringImpl LT EQ GT
instance ordChar :: Ord Char where
compare = ordCharImpl LT EQ GT
instance ordUnit :: Ord Unit where
compare _ _ = EQ
instance ordVoid :: Ord Void where
compare _ _ = EQ
instance ordProxy :: Ord (Proxy a) where
compare _ _ = EQ
instance ordArray :: Ord a => Ord (Array a) where
compare = \xs ys -> compare 0 (ordArrayImpl toDelta xs ys)
where
toDelta x y =
case compare x y of
EQ -> 0
LT -> 1
GT -> -1
foreign import ordBooleanImpl
:: Ordering
-> Ordering
-> Ordering
-> Boolean
-> Boolean
-> Ordering
foreign import ordIntImpl
:: Ordering
-> Ordering
-> Ordering
-> Int
-> Int
-> Ordering
foreign import ordNumberImpl
:: Ordering
-> Ordering
-> Ordering
-> Number
-> Number
-> Ordering
foreign import ordStringImpl
:: Ordering
-> Ordering
-> Ordering
-> String
-> String
-> Ordering
foreign import ordCharImpl
:: Ordering
-> Ordering
-> Ordering
-> Char
-> Char
-> Ordering
foreign import ordArrayImpl :: forall a. (a -> a -> Int) -> Array a -> Array a -> Int
instance ordOrdering :: Ord Ordering where
compare LT LT = EQ
compare EQ EQ = EQ
compare GT GT = EQ
compare LT _ = LT
compare EQ LT = GT
compare EQ GT = LT
compare GT _ = GT
-- | Test whether one value is _strictly less than_ another.
lessThan :: forall a. Ord a => a -> a -> Boolean
lessThan a1 a2 = case a1 `compare` a2 of
LT -> true
_ -> false
-- | Test whether one value is _strictly greater than_ another.
greaterThan :: forall a. Ord a => a -> a -> Boolean
greaterThan a1 a2 = case a1 `compare` a2 of
GT -> true
_ -> false
-- | Test whether one value is _non-strictly less than_ another.
lessThanOrEq :: forall a. Ord a => a -> a -> Boolean
lessThanOrEq a1 a2 = case a1 `compare` a2 of
GT -> false
_ -> true
-- | Test whether one value is _non-strictly greater than_ another.
greaterThanOrEq :: forall a. Ord a => a -> a -> Boolean
greaterThanOrEq a1 a2 = case a1 `compare` a2 of
LT -> false
_ -> true
infixl 4 lessThan as <
infixl 4 lessThanOrEq as <=
infixl 4 greaterThan as >
infixl 4 greaterThanOrEq as >=
-- | Compares two values by mapping them to a type with an `Ord` instance.
comparing :: forall a b. Ord b => (a -> b) -> (a -> a -> Ordering)
comparing f x y = compare (f x) (f y)
-- | Take the minimum of two values. If they are considered equal, the first
-- | argument is chosen.
min :: forall a. Ord a => a -> a -> a
min x y =
case compare x y of
LT -> x
EQ -> x
GT -> y
-- | Take the maximum of two values. If they are considered equal, the first
-- | argument is chosen.
max :: forall a. Ord a => a -> a -> a
max x y =
case compare x y of
LT -> y
EQ -> x
GT -> x
-- | Clamp a value between a minimum and a maximum. For example:
-- |
-- | ``` purescript
-- | let f = clamp 0 10
-- | f (-5) == 0
-- | f 5 == 5
-- | f 15 == 10
-- | ```
clamp :: forall a. Ord a => a -> a -> a -> a
clamp low hi x = min hi (max low x)
-- | Test whether a value is between a minimum and a maximum (inclusive).
-- | For example:
-- |
-- | ``` purescript
-- | let f = between 0 10
-- | f 0 == true
-- | f (-5) == false
-- | f 5 == true
-- | f 10 == true
-- | f 15 == false
-- | ```
between :: forall a. Ord a => a -> a -> a -> Boolean
between low hi x
| x < low = false
| x > hi = false
| true = true
-- | The absolute value function. `abs x` is defined as `if x >= zero then x
-- | else negate x`.
abs :: forall a. Ord a => Ring a => a -> a
abs x = if x >= zero then x else negate x
-- | The sign function; returns `one` if the argument is positive,
-- | `negate one` if the argument is negative, or `zero` if the argument is `zero`.
-- | For floating point numbers with signed zeroes, when called with a zero,
-- | this function returns the argument in order to preserve the sign.
-- | For any `x`, we should have `signum x * abs x == x`.
signum :: forall a. Ord a => Ring a => a -> a
signum x =
if x < zero then negate one
else if x > zero then one
else x
-- | The `Ord1` type class represents totally ordered type constructors.
class Eq1 f <= Ord1 f where
compare1 :: forall a. Ord a => f a -> f a -> Ordering
instance ord1Array :: Ord1 Array where
compare1 = compare
class OrdRecord :: RL.RowList Type -> Row Type -> Constraint
class EqRecord rowlist row <= OrdRecord rowlist row where
compareRecord :: Proxy rowlist -> Record row -> Record row -> Ordering
instance ordRecordNil :: OrdRecord RL.Nil row where
compareRecord _ _ _ = EQ
instance ordRecordCons ::
( OrdRecord rowlistTail row
, Row.Cons key focus rowTail row
, IsSymbol key
, Ord focus
) =>
OrdRecord (RL.Cons key focus rowlistTail) row where
compareRecord _ ra rb =
if left /= EQ then left
else compareRecord (Proxy :: Proxy rowlistTail) ra rb
where
key = reflectSymbol (Proxy :: Proxy key)
unsafeGet' = unsafeGet :: String -> Record row -> focus
left = unsafeGet' key ra `compare` unsafeGet' key rb
instance ordRecord ::
( RL.RowToList row list
, OrdRecord list row
) =>
Ord (Record row) where
compare = compareRecord (Proxy :: Proxy list)