"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ordDate = exports.ordNumber = exports.ordString = exports.ordBoolean = exports.ord = exports.getDualOrd = exports.getTupleOrd = exports.between = exports.clamp = exports.max = exports.min = exports.geq = exports.leq = exports.gt = exports.lt = exports.equals = exports.trivial = exports.Contravariant = exports.getMonoid = exports.getSemigroup = exports.URI = exports.contramap = exports.reverse = exports.tuple = exports.fromCompare = exports.equalsDefault = void 0; var Eq_1 = require("./Eq"); var function_1 = require("./function"); // ------------------------------------------------------------------------------------- // defaults // ------------------------------------------------------------------------------------- /** * @category defaults * @since 2.10.0 */ var equalsDefault = function (compare) { return function (first, second) { return first === second || compare(first, second) === 0; }; }; exports.equalsDefault = equalsDefault; // ------------------------------------------------------------------------------------- // constructors // ------------------------------------------------------------------------------------- /** * @category constructors * @since 2.0.0 */ var fromCompare = function (compare) { return ({ equals: (0, exports.equalsDefault)(compare), compare: function (first, second) { return (first === second ? 0 : compare(first, second)); } }); }; exports.fromCompare = fromCompare; // ------------------------------------------------------------------------------------- // combinators // ------------------------------------------------------------------------------------- /** * Given a tuple of `Ord`s returns an `Ord` for the tuple. * * @example * import { tuple } from 'fp-ts/Ord' * import * as B from 'fp-ts/boolean' * import * as S from 'fp-ts/string' * import * as N from 'fp-ts/number' * * const O = tuple(S.Ord, N.Ord, B.Ord) * assert.strictEqual(O.compare(['a', 1, true], ['b', 2, true]), -1) * assert.strictEqual(O.compare(['a', 1, true], ['a', 2, true]), -1) * assert.strictEqual(O.compare(['a', 1, true], ['a', 1, false]), 1) * * @since 2.10.0 */ var tuple = function () { var ords = []; for (var _i = 0; _i < arguments.length; _i++) { ords[_i] = arguments[_i]; } return (0, exports.fromCompare)(function (first, second) { var i = 0; for (; i < ords.length - 1; i++) { var r = ords[i].compare(first[i], second[i]); if (r !== 0) { return r; } } return ords[i].compare(first[i], second[i]); }); }; exports.tuple = tuple; /** * @since 2.10.0 */ var reverse = function (O) { return (0, exports.fromCompare)(function (first, second) { return O.compare(second, first); }); }; exports.reverse = reverse; /* istanbul ignore next */ var contramap_ = function (fa, f) { return (0, function_1.pipe)(fa, (0, exports.contramap)(f)); }; /** * A typical use case for `contramap` would be like, given some `User` type, to construct an `Ord`. * * We can do so with a function from `User -> X` where `X` is some value that we know how to compare * for ordering (meaning we have an `Ord`) * * For example, given the following `User` type, there are lots of possible choices for `X`, * but let's say we want to sort a list of users by `lastName`. * * If we have a way of comparing `lastName`s for ordering (`ordLastName: Ord`) and we know how to go from `User -> string`, * using `contramap` we can do this * * @example * import { pipe } from 'fp-ts/function' * import { contramap, Ord } from 'fp-ts/Ord' * import * as RA from 'fp-ts/ReadonlyArray' * import * as S from 'fp-ts/string' * * interface User { * readonly firstName: string * readonly lastName: string * } * * const ordLastName: Ord = S.Ord * * const ordByLastName: Ord = pipe( * ordLastName, * contramap((user) => user.lastName) * ) * * assert.deepStrictEqual( * RA.sort(ordByLastName)([ * { firstName: 'a', lastName: 'd' }, * { firstName: 'c', lastName: 'b' } * ]), * [ * { firstName: 'c', lastName: 'b' }, * { firstName: 'a', lastName: 'd' } * ] * ) * * @since 2.0.0 */ var contramap = function (f) { return function (fa) { return (0, exports.fromCompare)(function (first, second) { return fa.compare(f(first), f(second)); }); }; }; exports.contramap = contramap; /** * @category type lambdas * @since 2.0.0 */ exports.URI = 'Ord'; /** * A typical use case for the `Semigroup` instance of `Ord` is merging two or more orderings. * * For example the following snippet builds an `Ord` for a type `User` which * sorts by `created` date descending, and **then** `lastName` * * @example * import * as D from 'fp-ts/Date' * import { pipe } from 'fp-ts/function' * import { contramap, getSemigroup, Ord, reverse } from 'fp-ts/Ord' * import * as RA from 'fp-ts/ReadonlyArray' * import * as S from 'fp-ts/string' * * interface User { * readonly id: string * readonly lastName: string * readonly created: Date * } * * const ordByLastName: Ord = pipe( * S.Ord, * contramap((user) => user.lastName) * ) * * const ordByCreated: Ord = pipe( * D.Ord, * contramap((user) => user.created) * ) * * const ordUserByCreatedDescThenLastName = getSemigroup().concat( * reverse(ordByCreated), * ordByLastName * ) * * assert.deepStrictEqual( * RA.sort(ordUserByCreatedDescThenLastName)([ * { id: 'c', lastName: 'd', created: new Date(1973, 10, 30) }, * { id: 'a', lastName: 'b', created: new Date(1973, 10, 30) }, * { id: 'e', lastName: 'f', created: new Date(1980, 10, 30) } * ]), * [ * { id: 'e', lastName: 'f', created: new Date(1980, 10, 30) }, * { id: 'a', lastName: 'b', created: new Date(1973, 10, 30) }, * { id: 'c', lastName: 'd', created: new Date(1973, 10, 30) } * ] * ) * * @category instances * @since 2.0.0 */ var getSemigroup = function () { return ({ concat: function (first, second) { return (0, exports.fromCompare)(function (a, b) { var ox = first.compare(a, b); return ox !== 0 ? ox : second.compare(a, b); }); } }); }; exports.getSemigroup = getSemigroup; /** * Returns a `Monoid` such that: * * - its `concat(ord1, ord2)` operation will order first by `ord1`, and then by `ord2` * - its `empty` value is an `Ord` that always considers compared elements equal * * @example * import { sort } from 'fp-ts/Array' * import { contramap, reverse, getMonoid } from 'fp-ts/Ord' * import * as S from 'fp-ts/string' * import * as B from 'fp-ts/boolean' * import { pipe } from 'fp-ts/function' * import { concatAll } from 'fp-ts/Monoid' * import * as N from 'fp-ts/number' * * interface User { * readonly id: number * readonly name: string * readonly age: number * readonly rememberMe: boolean * } * * const byName = pipe( * S.Ord, * contramap((p: User) => p.name) * ) * * const byAge = pipe( * N.Ord, * contramap((p: User) => p.age) * ) * * const byRememberMe = pipe( * B.Ord, * contramap((p: User) => p.rememberMe) * ) * * const M = getMonoid() * * const users: Array = [ * { id: 1, name: 'Guido', age: 47, rememberMe: false }, * { id: 2, name: 'Guido', age: 46, rememberMe: true }, * { id: 3, name: 'Giulio', age: 44, rememberMe: false }, * { id: 4, name: 'Giulio', age: 44, rememberMe: true } * ] * * // sort by name, then by age, then by `rememberMe` * const O1 = concatAll(M)([byName, byAge, byRememberMe]) * assert.deepStrictEqual(sort(O1)(users), [ * { id: 3, name: 'Giulio', age: 44, rememberMe: false }, * { id: 4, name: 'Giulio', age: 44, rememberMe: true }, * { id: 2, name: 'Guido', age: 46, rememberMe: true }, * { id: 1, name: 'Guido', age: 47, rememberMe: false } * ]) * * // now `rememberMe = true` first, then by name, then by age * const O2 = concatAll(M)([reverse(byRememberMe), byName, byAge]) * assert.deepStrictEqual(sort(O2)(users), [ * { id: 4, name: 'Giulio', age: 44, rememberMe: true }, * { id: 2, name: 'Guido', age: 46, rememberMe: true }, * { id: 3, name: 'Giulio', age: 44, rememberMe: false }, * { id: 1, name: 'Guido', age: 47, rememberMe: false } * ]) * * @category instances * @since 2.4.0 */ var getMonoid = function () { return ({ concat: (0, exports.getSemigroup)().concat, empty: (0, exports.fromCompare)(function () { return 0; }) }); }; exports.getMonoid = getMonoid; /** * @category instances * @since 2.7.0 */ exports.Contravariant = { URI: exports.URI, contramap: contramap_ }; // ------------------------------------------------------------------------------------- // utils // ------------------------------------------------------------------------------------- /** * @since 2.11.0 */ exports.trivial = { equals: function_1.constTrue, compare: /*#__PURE__*/ (0, function_1.constant)(0) }; /** * @since 2.11.0 */ var equals = function (O) { return function (second) { return function (first) { return first === second || O.compare(first, second) === 0; }; }; }; exports.equals = equals; // TODO: curry in v3 /** * Test whether one value is _strictly less than_ another * * @since 2.0.0 */ var lt = function (O) { return function (first, second) { return O.compare(first, second) === -1; }; }; exports.lt = lt; // TODO: curry in v3 /** * Test whether one value is _strictly greater than_ another * * @since 2.0.0 */ var gt = function (O) { return function (first, second) { return O.compare(first, second) === 1; }; }; exports.gt = gt; // TODO: curry in v3 /** * Test whether one value is _non-strictly less than_ another * * @since 2.0.0 */ var leq = function (O) { return function (first, second) { return O.compare(first, second) !== 1; }; }; exports.leq = leq; // TODO: curry in v3 /** * Test whether one value is _non-strictly greater than_ another * * @since 2.0.0 */ var geq = function (O) { return function (first, second) { return O.compare(first, second) !== -1; }; }; exports.geq = geq; // TODO: curry in v3 /** * Take the minimum of two values. If they are considered equal, the first argument is chosen * * @since 2.0.0 */ var min = function (O) { return function (first, second) { return first === second || O.compare(first, second) < 1 ? first : second; }; }; exports.min = min; // TODO: curry in v3 /** * Take the maximum of two values. If they are considered equal, the first argument is chosen * * @since 2.0.0 */ var max = function (O) { return function (first, second) { return first === second || O.compare(first, second) > -1 ? first : second; }; }; exports.max = max; /** * Clamp a value between a minimum and a maximum * * @since 2.0.0 */ var clamp = function (O) { var minO = (0, exports.min)(O); var maxO = (0, exports.max)(O); return function (low, hi) { return function (a) { return maxO(minO(a, hi), low); }; }; }; exports.clamp = clamp; /** * Test whether a value is between a minimum and a maximum (inclusive) * * @since 2.0.0 */ var between = function (O) { var ltO = (0, exports.lt)(O); var gtO = (0, exports.gt)(O); return function (low, hi) { return function (a) { return ltO(a, low) || gtO(a, hi) ? false : true; }; }; }; exports.between = between; // ------------------------------------------------------------------------------------- // deprecated // ------------------------------------------------------------------------------------- /** * Use [`tuple`](#tuple) instead. * * @category zone of death * @since 2.0.0 * @deprecated */ exports.getTupleOrd = exports.tuple; /** * Use [`reverse`](#reverse) instead. * * @category zone of death * @since 2.0.0 * @deprecated */ exports.getDualOrd = exports.reverse; /** * Use [`Contravariant`](#contravariant) instead. * * @category zone of death * @since 2.0.0 * @deprecated */ exports.ord = exports.Contravariant; // default compare for primitive types function compare(first, second) { return first < second ? -1 : first > second ? 1 : 0; } var strictOrd = { equals: Eq_1.eqStrict.equals, compare: compare }; /** * Use [`Ord`](./boolean.ts.html#ord) instead. * * @category zone of death * @since 2.0.0 * @deprecated */ exports.ordBoolean = strictOrd; /** * Use [`Ord`](./string.ts.html#ord) instead. * * @category zone of death * @since 2.0.0 * @deprecated */ exports.ordString = strictOrd; /** * Use [`Ord`](./number.ts.html#ord) instead. * * @category zone of death * @since 2.0.0 * @deprecated */ exports.ordNumber = strictOrd; /** * Use [`Ord`](./Date.ts.html#ord) instead. * * @category zone of death * @since 2.0.0 * @deprecated */ exports.ordDate = (0, function_1.pipe)(exports.ordNumber, /*#__PURE__*/ (0, exports.contramap)(function (date) { return date.valueOf(); }));