// @flow import type { Setoid } from './Setoid' import type { Ordering } from './Ordering' import { booleanSetoid, numberSetoid, stringSetoid } from './Setoid' export type Comparator = (x: A, y: A) => Ordering; export type NativeComparator = (x: A, y: A) => number; export interface Ord extends Setoid { compare(x: A, y: A): Ordering } export function toNativeComparator(compare: Comparator): NativeComparator { return (x, y) => { const c = compare(x, y) return c === 'GT' ? 1 : c === 'EQ' ? 0 : -1 } } export function unsafeCompare(x: any, y: any): Ordering { return x < y ? 'LT' : x > y ? 'GT' : 'EQ' } export const booleanOrd: Ord = Object.assign({}, { compare: unsafeCompare }, booleanSetoid) export const numberOrd: Ord = Object.assign({}, { compare: unsafeCompare }, numberSetoid) export const stringOrd: Ord = Object.assign({}, { compare: unsafeCompare }, stringSetoid) export function lessThan(ord: Ord, x: A, y: A): boolean { return ord.compare(x, y) === 'LT' } export function greaterThan(ord: Ord, x: A, y: A): boolean { return ord.compare(x, y) === 'GT' } export function lessThanOrEq(ord: Ord, x: A, y: A): boolean { return ord.compare(x, y) !== 'GT' } export function greaterThanOrEq(ord: Ord, x: A, y: A): boolean { return ord.compare(x, y) !== 'LT' } export function min(ord: Ord, x: A, y: A): A { return ord.compare(x, y) === 'GT' ? y : x } export function max(ord: Ord, x: A, y: A): A { return ord.compare(x, y) === 'LT' ? y : x } export function clamp(ord: Ord, low: A, hi: A, x: A): A { return min(ord, hi, max(ord, low, x)) } export function between(ord: Ord, low: A, hi: A, x: A): boolean { return lessThan(ord, x, low) || greaterThan(ord, x, hi) ? false : true }