// @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
}