import * as E from "@principia/prelude/Eq"; import { memoize } from "../_utils"; import * as A from "../Array"; import type { ReadonlyRecord } from "../Record"; import * as R from "../Record"; import type { Eq } from "./model"; /* * ------------------------------------------- * Eq Combinators * ------------------------------------------- */ export * from "@principia/prelude/Eq/combinators"; export const nullable = (or: Eq): Eq => E.fromEquals((x, y) => (x === null || y === null ? x === y : or.equals_(x, y))); export const type: (eqs: { [K in keyof A]: Eq }) => Eq<{ [K in keyof A]: A[K] }> = E.getStructEq; export const partial = (properties: { [K in keyof A]: Eq }): Eq> => E.fromEquals((x, y) => { for (const k in properties) { const xk = x[k]; const yk = y[k]; if (!(xk === undefined || yk === undefined ? xk === yk : properties[k].equals_(xk!, yk!))) { return false; } } return true; }); export const record: (codomain: Eq) => Eq> = R.getEq; export const array: (item: Eq) => Eq> = A.getEq; export const tuple: >( ...components: { [K in keyof A]: Eq } ) => Eq = E.getTupleEq as any; export const intersect_ = (left: Eq, right: Eq): Eq => E.fromEquals((x, y) => left.equals_(x, y) && right.equals_(x, y)); export const intersect = (right: Eq) => (left: Eq): Eq => intersect_(left, right); export const sum_ = ( tag: T, members: { [K in keyof A]: Eq> } ): Eq => E.fromEquals((x: ReadonlyRecord, y: ReadonlyRecord) => { const vx = x[tag]; const vy = y[tag]; if (vx !== vy) { return false; } return members[vx].equals(x, y); }); export const sum = (tag: T) => ( members: { [K in keyof A]: Eq> } ): Eq => sum_(tag, members); export const lazy = (f: () => Eq): Eq => { const get = memoize>(f); return E.fromEquals((x, y) => get().equals_(x, y)); };