1/**
2 * Defines comparison functions for ordered values.
3 *
4 * An `Order<A>` compares two `A` values and returns whether the first is less
5 * than, equal to, or greater than the second. Orders are used for sorting,
6 * choosing minimum or maximum values, checking ranges, and building ordered data
7 * structures. This module includes built-in orders, constructors for custom
8 * orders, tools for reversing and combining comparisons, tuple and struct
9 * helpers, comparison predicates, clamping, and reducer support.
10 *
11 * @since 2.0.0
12 */
13import { dual } from "./Function.ts"
14import type { TypeLambda } from "./HKT.ts"
15import type { Ordering } from "./Ordering.ts"
16import * as Reducer from "./Reducer.ts"
17
18/**
19 * Represents a total ordering for values of type `A`.
20 *
21 * **When to use**
22 *
23 * Use when you need to define how values of a type are compared.
24 *
25 * **Details**
26 *
27 * An order returns `-1` when the first value is less than the second, `0` when
28 * the values are equal according to this ordering, and `1` when the first value
29 * is greater than the second. It must satisfy total ordering laws: totality,
30 * antisymmetry, and transitivity.
31 *
32 * **Example** (Defining a custom Order)
33 *
34 * ```ts import.meta.vitest
35 * import { Order } from "effect"
36 *
37 * const byAge: Order.Order<{ name: string; age: number }> = (self, that) => {
38 * if (self.age < that.age) return -1
39 * if (self.age > that.age) return 1
40 * return 0
41 * }
42 *
43 * const person1 = { name: "Alice", age: 30 }
44 * const person2 = { name: "Bob", age: 25 }
45 * byAge(person1, person2) // => 1
46 * ```
47 *
48 * @see {@link make} to create an order from a comparison function
49 * @see {@link Ordering} for the result type of comparisons
50 * @category models
51 * @since 2.0.0
52 */
53export interface Order<in A> {
54 (self: A, that: A): Ordering
55}
56
57/**
58 * Type lambda for the `Order` type class, used internally for higher-kinded type operations.
59 *
60 * **When to use**
61 *
62 * Use when you need to abstract over `Order` in higher-kinded type code.
63 *
64 * **Details**
65 *
66 * This is type-level only, has no runtime representation, and is used
67 * internally by the Effect type system.
68 *
69 * @category utility types
70 * @since 2.0.0
71 */
72export interface OrderTypeLambda extends TypeLambda {
73 readonly type: Order<this["Target"]>
74}
75
76/**
77 * Creates a new `Order` instance from a comparison function.
78 *
79 * **When to use**
80 *
81 * Use when you need a sorting rule not covered by the built-in orders or input
82 * mapping helpers, and you can provide a total comparison.
83 *
84 * **Details**
85 *
86 * Uses reference equality (`===`) as a shortcut: if `self === that`, it returns
87 * `0` without calling the comparison function. The comparison function should
88 * return `-1`, `0`, or `1`, and the returned order satisfies total ordering
89 * laws when the comparison function does.
90 *
91 * **Example** (Creating an Order)
92 *
93 * ```ts import.meta.vitest
94 * import { Order } from "effect"
95 *
96 * const byAge = Order.make<{ name: string; age: number }>((self, that) => {
97 * if (self.age < that.age) return -1
98 * if (self.age > that.age) return 1
99 * return 0
100 * })
101 *
102 * byAge({ name: "Alice", age: 30 }, { name: "Bob", age: 25 }) // => 1
103 * byAge({ name: "Alice", age: 25 }, { name: "Bob", age: 30 }) // => -1
104 * ```
105 *
106 * @see {@link mapInput} to transform an order by mapping the input type
107 * @see {@link combine} to combine multiple orders
108 * @category constructors
109 * @since 2.0.0
110 */
111export function make<A>(
112 compare: (self: A, that: A) => -1 | 0 | 1
113): Order<A> {
114 return (self, that) => self === that ? 0 : compare(self, that)
115}
116
117/**
118 * Order instance for strings that compares them lexicographically using JavaScript's `<` operator.
119 *
120 * **When to use**
121 *
122 * Use when you need lexicographic string ordering.
123 *
124 * **Details**
125 *
126 * Uses lexicographic dictionary ordering. The empty string is less than any
127 * non-empty string, and comparisons are case-sensitive.
128 *
129 * **Example** (Ordering strings)
130 *
131 * ```ts import.meta.vitest
132 * import { Order } from "effect"
133 *
134 * Order.String("apple", "banana") // => -1
135 * Order.String("banana", "apple") // => 1
136 * Order.String("apple", "apple") // => 0
137 * ```
138 *
139 * @see {@link mapInput} to compare objects by a string property
140 * @see {@link Struct} to combine with other orders for struct comparison
141 * @category instances
142 * @since 4.0.0
143 */
144export const String: Order<string> = make((self, that) => self < that ? -1 : 1)
145
146/**
147 * Order instance for numbers that compares them numerically.
148 *
149 * **When to use**
150 *
151 * Use when you need numeric ordering for numbers.
152 *
153 * **Details**
154 *
155 * `0` is considered equal to `-0`. All `NaN` values are considered equal to
156 * each other, and any `NaN` is considered less than any non-`NaN` number. All
157 * other values use standard numeric comparison.
158 *
159 * **Example** (Ordering numbers)
160 *
161 * ```ts import.meta.vitest
162 * import { Order } from "effect"
163 *
164 * Order.Number(1, 1) // => 0
165 * Order.Number(1, 2) // => -1
166 * Order.Number(2, 1) // => 1
167 *
168 * Order.Number(0, -0) // => 0
169 * Order.Number(NaN, 1) // => -1
170 * ```
171 *
172 * @see {@link mapInput} to compare objects by a number property
173 * @see {@link BigInt} for bigint comparisons
174 * @category instances
175 * @since 4.0.0
176 */
177export const Number: Order<number> = make((self, that) => {
178 if (globalThis.Number.isNaN(self) && globalThis.Number.isNaN(that)) return 0
179 if (globalThis.Number.isNaN(self)) return -1 // NaN < any number
180 if (globalThis.Number.isNaN(that)) return 1 // any number > NaN
181 return self < that ? -1 : 1
182})
183
184/**
185 * Order instance for booleans where `false` is considered less than `true`.
186 *
187 * **When to use**
188 *
189 * Use when you need boolean ordering where `false` comes before `true`.
190 *
191 * **Details**
192 *
193 * `false` is less than `true`, and equal values return `0`.
194 *
195 * **Example** (Ordering booleans)
196 *
197 * ```ts import.meta.vitest
198 * import { Order } from "effect"
199 *
200 * Order.Boolean(false, true) // => -1
201 * Order.Boolean(true, false) // => 1
202 * Order.Boolean(true, true) // => 0
203 * ```
204 *
205 * @see {@link mapInput} to compare objects by a boolean property
206 * @category instances
207 * @since 4.0.0
208 */
209export const Boolean: Order<boolean> = make((self, that) => self < that ? -1 : 1)
210
211/**
212 * Order instance for bigints that compares them numerically.
213 *
214 * **When to use**
215 *
216 * Use when you need numeric ordering for `bigint` values.
217 *
218 * **Details**
219 *
220 * Uses standard numeric comparison for bigint values and handles arbitrarily
221 * large integers.
222 *
223 * **Example** (Ordering BigInts)
224 *
225 * ```ts import.meta.vitest
226 * import { Order } from "effect"
227 *
228 * Order.BigInt(1n, 2n) // => -1
229 * Order.BigInt(2n, 1n) // => 1
230 * Order.BigInt(1n, 1n) // => 0
231 * ```
232 *
233 * @see {@link Number} for regular number comparisons
234 * @see {@link mapInput} to compare objects by a bigint property
235 * @category instances
236 * @since 4.0.0
237 */
238export const BigInt: Order<bigint> = make((self, that) => self < that ? -1 : 1)
239
240/**
241 * Creates a new `Order` that reverses the comparison order of the input `Order`.
242 *
243 * **When to use**
244 *
245 * Use when you need the reverse of an existing order.
246 *
247 * **Details**
248 *
249 * Returns a new order that swaps the arguments before comparison. If the
250 * original order returns `-1`, the flipped order returns `1`, and vice versa.
251 * Equal comparisons remain `0`.
252 *
253 * **Example** (Reversing an Order)
254 *
255 * ```ts import.meta.vitest
256 * import { Order } from "effect"
257 *
258 * const flip = Order.flip(Order.Number)
259 *
260 * flip(1, 2) // => 1
261 * flip(2, 1) // => -1
262 * flip(1, 1) // => 0
263 * ```
264 *
265 * @see {@link combine} to combine orders for multi-criteria comparison
266 * @category combinators
267 * @since 4.0.0
268 */
269export function flip<A>(O: Order<A>): Order<A> {
270 return make((self, that) => O(that, self))
271}
272
273/**
274 * Combines two `Order` instances to create a new `Order` that first compares using the first `Order`,
275 * and if the values are equal, then compares using the second `Order`.
276 *
277 * **When to use**
278 *
279 * Use when you need tie-breaking with exactly two orders.
280 *
281 * **Details**
282 *
283 * First applies the first order. If the result is non-zero, that result is
284 * returned; otherwise, the second order is applied. The result is the first
285 * non-zero comparison result, or `0` if both orders return `0`.
286 *
287 * **Example** (Combining two Orders)
288 *
289 * ```ts import.meta.vitest
290 * import { Order } from "effect"
291 *
292 * const byAge = Order.mapInput(
293 * Order.Number,
294 * (person: { name: string; age: number }) => person.age
295 * )
296 * const byName = Order.mapInput(
297 * Order.String,
298 * (person: { name: string; age: number }) => person.name
299 * )
300 * const byAgeAndName = Order.combine(byAge, byName)
301 *
302 * const person1 = { name: "Alice", age: 30 }
303 * const person2 = { name: "Bob", age: 30 }
304 * const person3 = { name: "Charlie", age: 25 }
305 *
306 * byAgeAndName(person1, person2) // => -1
307 * byAgeAndName(person1, person3) // => 1
308 * ```
309 *
310 * @see {@link combineAll} to combine multiple orders from a collection
311 * @see {@link mapInput} to transform orders to work with different types
312 * @category combining
313 * @since 2.0.0
314 */
315export const combine: {
316 <A>(that: Order<A>): (self: Order<A>) => Order<A>
317 <A>(self: Order<A>, that: Order<A>): Order<A>
318} = dual(2, <A>(self: Order<A>, that: Order<A>): Order<A> =>
319 make((a1, a2) => {
320 const out = self(a1, a2)
321 if (out !== 0) {
322 return out
323 }
324 return that(a1, a2)
325 }))
326
327/**
328 * Creates an `Order` that considers all values as equal.
329 *
330 * **When to use**
331 *
332 * Use when you need an order that treats all values as equal.
333 *
334 * **Details**
335 *
336 * Always returns `0` regardless of input values, making it useful as a neutral
337 * element in order composition.
338 *
339 * **Example** (Ordering with an always-equal Order)
340 *
341 * ```ts import.meta.vitest
342 * import { Order } from "effect"
343 *
344 * const alwaysEqualOrder = Order.alwaysEqual<number>()
345 *
346 * alwaysEqualOrder(1, 2) // => 0
347 * alwaysEqualOrder(2, 1) // => 0
348 * alwaysEqualOrder(1, 1) // => 0
349 * ```
350 *
351 * @see {@link combine} to combine with other orders
352 * @category constructors
353 * @since 4.0.0
354 */
355export function alwaysEqual<A>(): Order<A> {
356 return make(() => 0)
357}
358
359/**
360 * Combines all `Order` instances in the provided collection into a single `Order`.
361 * The resulting `Order` compares using each `Order` in sequence until a non-zero result is found.
362 *
363 * **When to use**
364 *
365 * Use when you need tie-breaking across a variable number of orders.
366 *
367 * **Details**
368 *
369 * Applies orders in iteration order and short-circuits on the first non-zero
370 * result. It returns `0` only if all orders return `0`.
371 * The collection is materialized when the order is created, so it must be finite.
372 *
373 * **Example** (Combining multiple Orders)
374 *
375 * ```ts import.meta.vitest
376 * import { Order } from "effect"
377 *
378 * const byAge = Order.mapInput(
379 * Order.Number,
380 * (person: { name: string; age: number }) => person.age
381 * )
382 * const byName = Order.mapInput(
383 * Order.String,
384 * (person: { name: string; age: number }) => person.name
385 * )
386 *
387 * const combinedOrder = Order.combineAll([byAge, byName])
388 *
389 * const person1 = { name: "Alice", age: 30 }
390 * const person2 = { name: "Bob", age: 30 }
391 *
392 * combinedOrder(person1, person2) // => -1
393 * ```
394 *
395 * @see {@link combine} to combine two orders
396 * @see {@link makeReducer} to create a reducer for combining orders
397 * @category combining
398 * @since 2.0.0
399 */
400export function combineAll<A>(collection: Iterable<Order<A>>): Order<A> {
401 const orders = Array.from(collection)
402 return make((a1, a2) => {
403 let out: Ordering = 0
404 for (const O of orders) {
405 out = O(a1, a2)
406 if (out !== 0) {
407 return out
408 }
409 }
410 return out
411 })
412}
413
414/**
415 * Transforms an `Order` on type `A` into an `Order` on type `B` by providing a function that
416 * maps values of type `B` to values of type `A`.
417 *
418 * **When to use**
419 *
420 * Use when you need to adapt an `Order` to compare a larger value by one
421 * derived property.
422 *
423 * **Details**
424 *
425 * Applies the mapping function to both values before comparison. The mapping
426 * function should be pure and not have side effects so the ordering properties
427 * of the original order are preserved.
428 *
429 * **Example** (Mapping Input)
430 *
431 * ```ts import.meta.vitest
432 * import { Order } from "effect"
433 *
434 * const byLength = Order.mapInput(Order.Number, (s: string) => s.length)
435 *
436 * byLength("a", "bb") // => -1
437 * byLength("bb", "a") // => 1
438 * byLength("aa", "bb") // => 0
439 * ```
440 *
441 * @see {@link combine} to combine mapped orders for multi-criteria comparison
442 * @see {@link Struct} to create orders for structs with multiple fields
443 * @category mapping
444 * @since 2.0.0
445 */
446export const mapInput: {
447 <B, A>(f: (b: B) => A): (self: Order<A>) => Order<B>
448 <A, B>(self: Order<A>, f: (b: B) => A): Order<B>
449} = dual(
450 2,
451 <A, B>(self: Order<A>, f: (b: B) => A): Order<B> => make((b1, b2) => self(f(b1), f(b2)))
452)
453
454/**
455 * Order instance for `Date` objects that compares them chronologically by their timestamp.
456 *
457 * **When to use**
458 *
459 * Use when you need chronological ordering for JavaScript date values.
460 *
461 * **Details**
462 *
463 * Compares dates by their underlying timestamp in milliseconds since the epoch.
464 * Earlier dates are less than later dates. Invalid dates are compared through
465 * their `getTime()` result.
466 *
467 * **Example** (Ordering Dates)
468 *
469 * ```ts import.meta.vitest
470 * import { Order } from "effect"
471 *
472 * const date1 = new Date("2023-01-01")
473 * const date2 = new Date("2023-01-02")
474 *
475 * Order.Date(date1, date2) // => -1
476 * Order.Date(date2, date1) // => 1
477 * Order.Date(date1, date1) // => 0
478 * ```
479 *
480 * @see {@link mapInput} to compare objects by a date property
481 * @category instances
482 * @since 2.0.0
483 */
484export const Date: Order<Date> = mapInput(Number, (date) => date.getTime())
485
486/**
487 * Creates an `Order` for a tuple type based on orders for each element.
488 *
489 * **When to use**
490 *
491 * Use when you need fixed-length tuple ordering with per-position orders.
492 *
493 * **Details**
494 *
495 * Compares tuples element-by-element using the corresponding order and stops at
496 * the first non-zero comparison result. Tuples must have the same length as the
497 * order collection, and the result is `0` only if all elements are equal.
498 *
499 * **Example** (Ordering tuples)
500 *
501 * ```ts import.meta.vitest
502 * import { Order } from "effect"
503 *
504 * const tupleOrder = Order.Tuple([Order.Number, Order.String])
505 *
506 * tupleOrder([1, "a"], [2, "b"]) // => -1
507 * tupleOrder([1, "b"], [1, "a"]) // => 1
508 * tupleOrder([1, "a"], [1, "a"]) // => 0
509 * ```
510 *
511 * @see {@link Array} to compare arrays with length consideration
512 * @category combinators
513 * @since 4.0.0
514 */
515export function Tuple<const Elements extends ReadonlyArray<Order<any>>>(
516 elements: Elements
517): Order<{ readonly [I in keyof Elements]: [Elements[I]] extends [Order<infer A>] ? A : never }> {
518 return make((self, that) => {
519 const len = elements.length
520 for (let i = 0; i < len; i++) {
521 const o = elements[i](self[i], that[i])
522 if (o !== 0) {
523 return o
524 }
525 }
526 return 0
527 })
528}
529
530/**
531 * @since 4.0.0
532 */
533function Array_<A>(O: Order<A>): Order<ReadonlyArray<A>> {
534 return make((self, that) => {
535 const aLen = self.length
536 const bLen = that.length
537 const len = Math.min(aLen, bLen)
538 for (let i = 0; i < len; i++) {
539 const o = O(self[i], that[i])
540 if (o !== 0) {
541 return o
542 }
543 }
544 return Number(aLen, bLen)
545 })
546}
547
548export {
549 /**
550 * Creates an `Order` for arrays by applying the given `Order` to each element, then comparing by length if all elements are equal.
551 *
552 * **When to use**
553 *
554 * Use when you need lexicographic ordering for arrays of one element type.
555 *
556 * **Details**
557 *
558 * Compares arrays element-by-element using the provided order and stops at the
559 * first non-zero comparison result. If all elements are equal, shorter arrays
560 * are less than longer arrays. The result is `0` only if arrays have the same
561 * length and all elements are equal.
562 *
563 * **Example** (Ordering array elements)
564 *
565 * ```ts import.meta.vitest
566 * import { Order } from "effect"
567 *
568 * const arrayOrder = Order.Array(Order.Number)
569 *
570 * arrayOrder([1, 2], [1, 3]) // => -1
571 * arrayOrder([1, 2], [1, 2, 3]) // => -1
572 * arrayOrder([1, 2, 3], [1, 2]) // => 1
573 * arrayOrder([1, 2], [1, 2]) // => 0
574 * ```
575 *
576 * @see {@link Tuple} for type-safe tuple ordering
577 * @category combinators
578 * @since 4.0.0
579 */
580 Array_ as Array
581}
582
583/**
584 * Creates an `Order` for structs by applying the given `Order`s to each property in sequence.
585 *
586 * **When to use**
587 *
588 * Use when you need multi-field ordering for objects with known properties.
589 *
590 * **Details**
591 *
592 * Compares structs field-by-field in the key order of the fields object and
593 * stops at the first non-zero comparison result. Field order matters: earlier
594 * fields take precedence. The result is `0` only if all fields are equal.
595 *
596 * **Example** (Ordering structs)
597 *
598 * ```ts import.meta.vitest
599 * import { Order } from "effect"
600 *
601 * const personOrder = Order.Struct({
602 * name: Order.String,
603 * age: Order.Number
604 * })
605 *
606 * const person1 = { name: "Alice", age: 30 }
607 * const person2 = { name: "Bob", age: 25 }
608 * const person3 = { name: "Alice", age: 25 }
609 *
610 * personOrder(person1, person2) // => -1
611 * personOrder(person1, person3) // => 1
612 * personOrder(person1, person1) // => 0
613 * ```
614 *
615 * @see {@link combine} to combine orders manually
616 * @see {@link mapInput} to extract and compare by a single property
617 * @category combinators
618 * @since 4.0.0
619 */
620export function Struct<const R extends { readonly [x: string]: Order<any> }>(
621 fields: R
622): Order<{ [K in keyof R]: [R[K]] extends [Order<infer A>] ? A : never }> {
623 const keys = Object.keys(fields)
624 return make((self, that) => {
625 for (const key of keys) {
626 const o = fields[key](self[key], that[key])
627 if (o !== 0) {
628 return o
629 }
630 }
631 return 0
632 })
633}
634
635/**
636 * Checks whether one value is strictly less than another according to the given order.
637 *
638 * **When to use**
639 *
640 * Use when you need a boolean less-than predicate using an `Order`.
641 *
642 * **Details**
643 *
644 * Returns `true` if the order returns `-1`, meaning the first value is less
645 * than the second. Equal or greater values return `false`.
646 *
647 * **Example** (Checking less-than comparisons)
648 *
649 * ```ts import.meta.vitest
650 * import { Order } from "effect"
651 *
652 * const isLessThanNumber = Order.isLessThan(Order.Number)
653 *
654 * isLessThanNumber(1, 2) // => true
655 * isLessThanNumber(2, 1) // => false
656 * isLessThanNumber(1, 1) // => false
657 * ```
658 *
659 * @see {@link isLessThanOrEqualTo} for non-strict less than or equal
660 * @see {@link isGreaterThan} for strict greater than
661 * @category predicates
662 * @since 4.0.0
663 */
664export const isLessThan = <A>(O: Order<A>): {
665 (that: A): (self: A) => boolean
666 (self: A, that: A): boolean
667} => dual(2, (self: A, that: A) => O(self, that) === -1)
668
669/**
670 * Checks whether one value is strictly greater than another according to the given order.
671 *
672 * **When to use**
673 *
674 * Use when you need a boolean greater-than predicate using an `Order`.
675 *
676 * **Details**
677 *
678 * Returns `true` if the order returns `1`, meaning the first value is greater
679 * than the second. Equal or lesser values return `false`.
680 *
681 * **Example** (Checking greater-than comparisons)
682 *
683 * ```ts import.meta.vitest
684 * import { Order } from "effect"
685 *
686 * const isGreaterThanNumber = Order.isGreaterThan(Order.Number)
687 *
688 * isGreaterThanNumber(2, 1) // => true
689 * isGreaterThanNumber(1, 2) // => false
690 * isGreaterThanNumber(1, 1) // => false
691 * ```
692 *
693 * @see {@link isGreaterThanOrEqualTo} for non-strict greater than or equal
694 * @see {@link isLessThan} for strict less than
695 * @category predicates
696 * @since 4.0.0
697 */
698export const isGreaterThan = <A>(O: Order<A>): {
699 (that: A): (self: A) => boolean
700 (self: A, that: A): boolean
701} => dual(2, (self: A, that: A) => O(self, that) === 1)
702
703/**
704 * Checks whether one value is less than or equal to another according to the given order.
705 *
706 * **When to use**
707 *
708 * Use when you need a boolean less-than-or-equal predicate using an `Order`.
709 *
710 * **Details**
711 *
712 * Returns `true` if the order returns `-1` or `0`, and returns `false` only if
713 * the order returns `1`.
714 *
715 * **Example** (Checking less-than-or-equal comparisons)
716 *
717 * ```ts import.meta.vitest
718 * import { Order } from "effect"
719 *
720 * const isLessThanOrEqualToNumber = Order.isLessThanOrEqualTo(Order.Number)
721 *
722 * isLessThanOrEqualToNumber(1, 2) // => true
723 * isLessThanOrEqualToNumber(1, 1) // => true
724 * isLessThanOrEqualToNumber(2, 1) // => false
725 * ```
726 *
727 * @see {@link isLessThan} for strict less than
728 * @see {@link isGreaterThan} for strict greater than
729 * @category predicates
730 * @since 4.0.0
731 */
732export const isLessThanOrEqualTo = <A>(O: Order<A>): {
733 (that: A): (self: A) => boolean
734 (self: A, that: A): boolean
735} => dual(2, (self: A, that: A) => O(self, that) !== 1)
736
737/**
738 * Checks whether one value is greater than or equal to another according to the given order.
739 *
740 * **When to use**
741 *
742 * Use when you need a boolean greater-than-or-equal predicate using an
743 * `Order`.
744 *
745 * **Details**
746 *
747 * Returns `true` if the order returns `1` or `0`, and returns `false` only if
748 * the order returns `-1`.
749 *
750 * **Example** (Checking greater-than-or-equal comparisons)
751 *
752 * ```ts import.meta.vitest
753 * import { Order } from "effect"
754 *
755 * const isGreaterThanOrEqualToNumber = Order.isGreaterThanOrEqualTo(Order.Number)
756 *
757 * isGreaterThanOrEqualToNumber(2, 1) // => true
758 * isGreaterThanOrEqualToNumber(1, 1) // => true
759 * isGreaterThanOrEqualToNumber(1, 2) // => false
760 * ```
761 *
762 * @see {@link isGreaterThan} for strict greater than
763 * @see {@link isLessThanOrEqualTo} for less than or equal
764 * @category predicates
765 * @since 4.0.0
766 */
767export const isGreaterThanOrEqualTo = <A>(O: Order<A>): {
768 (that: A): (self: A) => boolean
769 (self: A, that: A): boolean
770} => dual(2, (self: A, that: A) => O(self, that) !== -1)
771
772/**
773 * Returns the minimum of two values according to the given order. If they are equal, returns the first argument.
774 *
775 * **When to use**
776 *
777 * Use when you need to select the smaller of two values according to an
778 * `Order`.
779 *
780 * **Details**
781 *
782 * Returns the value that compares as less than or equal to the other value. If
783 * values are equal, the first argument is returned.
784 *
785 * **Example** (Selecting the minimum value)
786 *
787 * ```ts import.meta.vitest
788 * import { Order } from "effect"
789 *
790 * const minNumber = Order.min(Order.Number)
791 *
792 * minNumber(1, 2) // => 1
793 * minNumber(2, 1) // => 1
794 * minNumber(1, 1) // => 1
795 * ```
796 *
797 * @see {@link max} for the maximum of two values
798 * @see {@link clamp} to clamp a value between min and max
799 * @category comparisons
800 * @since 2.0.0
801 */
802export const min = <A>(O: Order<A>): {
803 (that: A): (self: A) => A
804 (self: A, that: A): A
805} => dual(2, (self: A, that: A) => self === that || O(self, that) < 1 ? self : that)
806
807/**
808 * Returns the maximum of two values according to the given order. If they are equal, returns the first argument.
809 *
810 * **When to use**
811 *
812 * Use when you need to select the larger of two values according to an
813 * `Order`.
814 *
815 * **Details**
816 *
817 * Returns the value that compares as greater than or equal to the other value.
818 * If values are equal, the first argument is returned.
819 *
820 * **Example** (Selecting the maximum value)
821 *
822 * ```ts import.meta.vitest
823 * import { Order } from "effect"
824 *
825 * const maxNumber = Order.max(Order.Number)
826 *
827 * maxNumber(1, 2) // => 2
828 * maxNumber(2, 1) // => 2
829 * maxNumber(1, 1) // => 1
830 * ```
831 *
832 * @see {@link min} for the minimum of two values
833 * @see {@link clamp} to clamp a value between min and max
834 * @category comparisons
835 * @since 2.0.0
836 */
837export const max = <A>(O: Order<A>): {
838 (that: A): (self: A) => A
839 (self: A, that: A): A
840} => dual(2, (self: A, that: A) => self === that || O(self, that) > -1 ? self : that)
841
842/**
843 * Restricts a value between a minimum and a maximum according to the given order.
844 *
845 * **When to use**
846 *
847 * Use when you need to clamp a value to an inclusive range according to an
848 * `Order`.
849 *
850 * **Details**
851 *
852 * Returns the value itself when it is between minimum and maximum, inclusive.
853 * Values below the range return minimum, and values above the range return
854 * maximum. The minimum must be less than or equal to the maximum according to
855 * the order.
856 *
857 * **Example** (Clamping values)
858 *
859 * ```ts import.meta.vitest
860 * import { Order } from "effect"
861 *
862 * const clamp = Order.clamp(Order.Number)({ minimum: 1, maximum: 5 })
863 *
864 * clamp(3) // => 3
865 * clamp(0) // => 1
866 * clamp(6) // => 5
867 * ```
868 *
869 * @see {@link min} for the minimum of two values
870 * @see {@link max} for the maximum of two values
871 * @see {@link isBetween} to check if a value is within a range
872 * @category comparisons
873 * @since 2.0.0
874 */
875export const clamp = <A>(O: Order<A>): {
876 (options: {
877 minimum: A
878 maximum: A
879 }): (self: A) => A
880 (self: A, options: {
881 minimum: A
882 maximum: A
883 }): A
884} =>
885 dual(
886 2,
887 (self: A, options: {
888 minimum: A
889 maximum: A
890 }): A => min(O)(options.maximum, max(O)(options.minimum, self))
891 )
892
893/**
894 * Checks whether a value is between a minimum and a maximum (inclusive) according to the given order.
895 *
896 * **When to use**
897 *
898 * Use when you need range checks that respect domain-specific ordering, such as
899 * dates, versions, or custom priorities, instead of JavaScript numeric
900 * comparison.
901 *
902 * **Details**
903 *
904 * Returns `true` when the value is greater than or equal to minimum and less
905 * than or equal to maximum. Values outside the range return `false`. Both
906 * bounds are inclusive.
907 *
908 * **Example** (Checking ranges)
909 *
910 * ```ts import.meta.vitest
911 * import { Order } from "effect"
912 *
913 * const betweenNumber = Order.isBetween(Order.Number)
914 *
915 * betweenNumber(5, { minimum: 1, maximum: 10 }) // => true
916 * betweenNumber(1, { minimum: 1, maximum: 10 }) // => true
917 * betweenNumber(10, { minimum: 1, maximum: 10 }) // => true
918 * betweenNumber(0, { minimum: 1, maximum: 10 }) // => false
919 * betweenNumber(11, { minimum: 1, maximum: 10 }) // => false
920 * ```
921 *
922 * @see {@link clamp} to clamp a value to a range
923 * @see {@link isLessThanOrEqualTo} for less than or equal check
924 * @see {@link isGreaterThanOrEqualTo} for greater than or equal check
925 * @category predicates
926 * @since 4.0.0
927 */
928export const isBetween = <A>(O: Order<A>): {
929 (options: {
930 minimum: A
931 maximum: A
932 }): (self: A) => boolean
933 (self: A, options: {
934 minimum: A
935 maximum: A
936 }): boolean
937} =>
938 dual(
939 2,
940 (self: A, options: {
941 minimum: A
942 maximum: A
943 }): boolean => !isLessThan(O)(self, options.minimum) && !isGreaterThan(O)(self, options.maximum)
944 )
945
946/**
947 * Creates a `Reducer` for combining `Order` instances, useful for aggregating orders in collections.
948 *
949 * **When to use**
950 *
951 * Use when you need a reducer that combines orders.
952 *
953 * **Details**
954 *
955 * Returns a reducer that combines orders using `combine`, uses `alwaysEqual` as
956 * the identity element for empty collections, and uses `combineAll` for
957 * combining collections of orders. The reducer can be used with fold operations
958 * on collections.
959 *
960 * **Example** (Creating a Reducer)
961 *
962 * ```ts import.meta.vitest
963 * import { Order } from "effect"
964 *
965 * const reducer = Order.makeReducer<number>()
966 * const orders = [Order.Number, Order.flip(Order.Number)]
967 *
968 * const combined = reducer.combineAll(orders)
969 * combined(1, 2) // => -1
970 * ```
971 *
972 * @see {@link combine} to combine two orders
973 * @see {@link combineAll} to combine multiple orders
974 * @see {@link Reducer} for reducing orders as a collection operation
975 * @category constructors
976 * @since 4.0.0
977 */
978export function makeReducer<A>() {
979 return Reducer.make<Order<A>>(
980 combine,
981 () => 0,
982 combineAll
983 )
984}