From bbaa58a0b8f99d23cc4888bfd17564229c8694ea Mon Sep 17 00:00:00 2001 From: Freywar Ulvnaudgari Date: Mon, 5 Aug 2024 21:39:52 +0300 Subject: [PATCH] Comparison functions --- src/bool.ts | 24 ++++- src/char.ts | 18 +++- src/list.ts | 52 ++++++++--- src/num.ts | 24 ++++- src/ord.ts | 31 +++++++ src/pair.ts | 48 ++++++++++ src/string.ts | 24 ++++- test/bool.spec.ts | 119 ++++++++++++++++++++++-- test/char.spec.ts | 149 +++++++++++++++++++++++++++++- test/core.spec.ts | 8 +- test/list.spec.ts | 211 +++++++++++++++++++++++++++++++++++++++++- test/num.spec.ts | 159 +++++++++++++++++++++++++++++++- test/pair.spec.ts | 163 ++++++++++++++++++++++++++++++++- test/string.spec.ts | 217 ++++++++++++++++++++++++++++++++++++++++++-- 14 files changed, 1188 insertions(+), 59 deletions(-) create mode 100644 src/ord.ts diff --git a/src/bool.ts b/src/bool.ts index 427971c..525187a 100644 --- a/src/bool.ts +++ b/src/bool.ts @@ -1,4 +1,5 @@ -import { toNative as $n, L, P, _, fromNative as _n } from './core'; +import { toNative as $$, L, P, _, fromNative as __ } from './core'; +import { EQ, GT, LT, Ord } from './ord'; export type Bool = L<(t: T) => L<(f: T) => T>>; @@ -11,11 +12,26 @@ export const False: Bool export const iif: L<(b: Bool) => L<(t: T) => L<(f: T) => T>>> = _(b => _(t => _(f => b._(t)._(f)))); +export const not: L<(b: Bool) => Bool> + = _(b => b._(False)._(True)); + +export const cmp: L<(l: Bool) => L<(r: Bool) => Ord>> + = _(l => _(r => l._(r._(EQ)._(GT))._(r._(LT)._(EQ)))); + +export const lt: L<(l: Bool) => L<(r: Bool) => Bool>> + = _(l => _(r => l._(False)._(r))); + +export const le: L<(l: Bool) => L<(r: Bool) => Bool>> + = _(l => _(r => l._(r)._(True))); + export const eq: L<(l: Bool) => L<(r: Bool) => Bool>> = _(l => _(r => l._(r)._(not._(r)))); -export const not: L<(b: Bool) => Bool> - = _(b => b._(False)._(True)); +export const ge: L<(l: Bool) => L<(r: Bool) => Bool>> + = _(l => _(r => l._(True)._(not._(r)))); + +export const gt: L<(l: Bool) => L<(r: Bool) => Bool>> + = _(l => _(r => l._(not._(r))._(False))); export const and: L<(l: Bool) => L<(r: Bool) => Bool>> = _(l => _(r => l._(r)._(False))); @@ -30,4 +46,4 @@ export const fromBoolean: (b: boolean) => Bool = b => b ? True : False; export const toBoolean: (b: Bool) => boolean - = b => $n(b._(_n(true))._(_n(false))); + = b => $$(b._(__(true))._(__(false))); diff --git a/src/char.ts b/src/char.ts index a34dfd6..8d65768 100644 --- a/src/char.ts +++ b/src/char.ts @@ -1,15 +1,31 @@ import { L, _ } from './core'; import { Bool } from './bool'; -import { toNumber as $n, Num, Zero, fromNumber as _n, eq as eqn } from './num'; +import { toNumber as $n, Num, Zero, fromNumber as _n, cmp as cmpn, eq as eqn, ge as gen, gt as gtn, le as len, lt as ltn } from './num'; +import { Ord } from 'src/ord'; export type Char = Num; export const Null: Char = Zero; +export const cmp: L<(l: Char) => L<(r: Char) => Ord>> + = cmpn; + +export const lt: L<(l: Char) => L<(r: Char) => Bool>> + = ltn; + +export const le: L<(l: Char) => L<(r: Char) => Bool>> + = len; + export const eq: L<(l: Char) => L<(r: Char) => Bool>> = eqn; +export const ge: L<(l: Char) => L<(r: Char) => Bool>> + = gen; + +export const gt: L<(l: Char) => L<(r: Char) => Bool>> + = gtn; + export const fromChar: (c: string) => Char = c => _n(c.charCodeAt(0)); diff --git a/src/list.ts b/src/list.ts index 477e92c..7924c5a 100644 --- a/src/list.ts +++ b/src/list.ts @@ -1,6 +1,6 @@ -import { toNative as $n, L, P, _, fromNative as _n, undef } from './core'; +import { toNative as $$, L, P, _, fromNative as __, undef } from './core'; +import { EQ, GT, LT, Ord, eq as eqc } from './ord'; import { Bool, False, True, and, iif, or } from './bool'; -import { toNumber as $nn, Num, fromNumber as _nn } from './num'; export type List = L<(z: R) => L<(f: L<(x: T) => L<(xs: List) => R>>) => R>>; @@ -42,12 +42,46 @@ export const foldr: L<(f: L<(x: T) => L<(a: R) => R>>) export const foldrz: L<(f: L<(x: T) => L<(a: T) => T>>) => L<(xs: List) => T>> = _(_f => _(_z => undef)); -export const eq: L<(e: L<(l: T) => L <(r: T) => Bool>>) => L<(l: List) => L<(r: List) => Bool>>> - = _((e: L<(l: T) => L<(r: T) => Bool>>) => +export const cmp: L<(ecmp: L<(l: T) => L <(r: T) => Ord>>) => L<(l: List) => L<(r: List) => Ord>>> + = _((ecmp: L<(l: T) => L<(r: T) => Ord>>) => + _((l: List) => + _((r: List) => l + ._(r._(EQ)._(_(_x => _(_xs => LT)))) + ._(_(lx => _(lxs => r._(GT)._(_(rx => _(rxs => iif + ._(eqc._(EQ)._(ecmp._(lx)._(rx))) + ._(cmp._(ecmp)._(lxs)._(rxs)) + ._(ecmp._(lx)._(rx))))))))))); + +export const lt: L<(ecmp: L<(l: T) => L <(r: T) => Ord>>) => L<(l: List) => L<(r: List) => Bool>>> + = _((ecmp: L<(l: T) => L<(r: T) => Ord>>) => + _((l: List) => + _((r: List) => + r._(False)._(_(rx => _(rxs => l._(True)._(_(lx => _(lxs => ecmp._(lx)._(rx)._(True)._(lt._(ecmp)._(lxs)._(rxs))._(False)))))))))); + +export const le: L<(ecmp: L<(l: T) => L <(r: T) => Ord>>) => L<(l: List) => L<(r: List) => Bool>>> + = _((ecmp: L<(l: T) => L<(r: T) => Ord>>) => + _((l: List) => + _((r: List) => + l._(True)._(_(lx => _(lxs => r._(False)._(_(rx => _(rxs => ecmp._(lx)._(rx)._(True)._(le._(ecmp)._(lxs)._(rxs))._(False)))))))))); + +export const eq: L<(eeq: L<(l: T) => L <(r: T) => Bool>>) => L<(l: List) => L<(r: List) => Bool>>> + = _((eeq: L<(l: T) => L<(r: T) => Bool>>) => _((l: List) => _((r: List) => l ._(r._(True)._(_(_x => _(_xs => False)))) - ._(_(lx => _(lxs => r._(False)._(_(rx => _(rxs => and._(e._(lx)._(rx))._(eq._(e)._(lxs)._(rxs))))))))))); + ._(_(lx => _(lxs => r._(False)._(_(rx => _(rxs => and._(eeq._(lx)._(rx))._(eq._(eeq)._(lxs)._(rxs))))))))))); + +export const ge: L<(ecmp: L<(l: T) => L <(r: T) => Ord>>) => L<(l: List) => L<(r: List) => Bool>>> + = _((ecmp: L<(l: T) => L<(r: T) => Ord>>) => + _((l: List) => + _((r: List) => + r._(True)._(_(rx => _(rxs => l._(False)._(_(lx => _(lxs => ecmp._(lx)._(rx)._(False)._(ge._(ecmp)._(lxs)._(rxs))._(True)))))))))); + +export const gt: L<(ecmp: L<(l: T) => L <(r: T) => Ord>>) => L<(l: List) => L<(r: List) => Bool>>> + = _((ecmp: L<(l: T) => L<(r: T) => Ord>>) => + _((l: List) => + _((r: List) => + l._(False)._(_(lx => _(lxs => r._(True)._(_(rx => _(rxs => ecmp._(lx)._(rx)._(False)._(gt._(ecmp)._(lxs)._(rxs))._(True)))))))))); export const map: L<(f: L<(x: T) => R>) => L<(xs: List) => List>> = _((f: L<(x: T) => R>) => @@ -68,11 +102,5 @@ export const all: L<(f: L<(x: T) => Bool>) => L<(xs: List) => Bo export const fromArray: (xs: T[]) => List = xs => xs.length === 0 ? Nil : Cons._(xs[0])._(new L(() => fromArray(xs.slice(1)).value)); -export const fromNumberArray: (xs: number[]) => List - = xs => xs.length === 0 ? Nil : Cons._(_nn(xs[0]))._(new L(() => fromNumberArray(xs.slice(1)).value)); - export const toArray: (xs: List) => P[] - = xs => $n(xs._(_n([]))._(_(x => _(xs => _n([x, ...toArray(xs)]))))); - -export const toNumberArray: (xs: List) => number[] - = xs => $n(xs._(_n([]))._(_(x => _(xs => _n([$nn(x), ...toNumberArray(xs)]))))); + = xs => $$(xs._(__([]))._(_(x => _(xs => __([x, ...toArray(xs)]))))); diff --git a/src/num.ts b/src/num.ts index 06ee70c..7206e9f 100644 --- a/src/num.ts +++ b/src/num.ts @@ -1,4 +1,5 @@ -import { toNative as $n, L, P, _, fromNative as _n, id } from './core'; +import { toNative as $$, L, P, _, fromNative as __, id } from './core'; +import { EQ, GT, LT, Ord } from './ord'; import { Bool, False, True } from './bool'; export type Num = L<(z: T) => L<(n: L<(p: Num) => T>) => T>>; @@ -18,10 +19,23 @@ export const succ: L<(n: Num) => Num> export const pred: L<(n: Num) => Num> = _(n => n._(Zero)._(id)); +export const cmp: L<(l: Num) => L<(r: Num) => Ord>> + = _(l => _(r => l._(r._(EQ)._(_(_ => LT)))._(_(pl => r._(GT)._(_(pr => cmp._(pl)._(pr))))))); + +export const lt: L<(l: Num) => L<(r: Num) => Bool>> + = _(l => _(r => r._(False)._(_(pr => l._(True)._(_(pl => lt._(pl)._(pr))))))); + +export const le: L<(l: Num) => L<(r: Num) => Bool>> + = _(l => _(r => l._(True)._(_(pl => r._(False)._(_(pr => le._(pl)._(pr))))))); + export const eq: L<(l: Num) => L<(r: Num) => Bool>> - = _(l => _(r => l - ._(r._(True)._(_(_ => False))) - ._(_(pl => r._(False)._(_(pr => eq._(pl)._(pr))))))); + = _(l => _(r => l._(r._(True)._(_(_ => False)))._(_(pl => r._(False)._(_(pr => eq._(pl)._(pr))))))); + +export const ge: L<(l: Num) => L<(r: Num) => Bool>> + = _(l => _(r => r._(True)._(_(pr => l._(False)._(_(pl => ge._(pl)._(pr))))))); + +export const gt: L<(l: Num) => L<(r: Num) => Bool>> + = _(l => _(r => l._(False)._(_(pl => r._(True)._(_(pr => gt._(pl)._(pr))))))); export const even: L<(n: Num) => Bool> = _(n => n._(True)._(odd)); @@ -42,4 +56,4 @@ export const fromNumber: (n: number) => Num = n => !n ? Zero : Succ._(new L(() => fromNumber(n - 1).value)); export const toNumber: (n: Num) => number - = n => $n(n._(_n(0))._(_(p => _n(1 + toNumber(p))))); + = n => $$(n._(__(0))._(_(p => __(1 + toNumber(p))))); diff --git a/src/ord.ts b/src/ord.ts new file mode 100644 index 0000000..6212096 --- /dev/null +++ b/src/ord.ts @@ -0,0 +1,31 @@ +import { toNative as $$, L, P, _, fromNative as __ } from './core'; +import { Bool, False, True } from './bool'; + +export type Ord = L<(lt: T) => L<(eq: T) => L<(gt: T) => T>>>; + +export const enum NOrd { + LT, + EQ, + GT, +}; + +export const LT: Ord + = _(lt => _(_eq => _(_gt => lt))) as Ord; + +export const EQ: Ord + = _(_lt => _(eq => _(_gt => eq))); + +export const GT: Ord + = _(_lt => _(_eq => _(gt => gt))); + +export const eq: L<(l: Ord) => L<(r: Ord) => Bool>> + = _(l => _(r => l + ._(r._(True)._(False)._(False)) + ._(r._(False)._(True)._(False)) + ._(r._(False)._(False)._(True)))); + +export const fromNOrd: (b: NOrd) => Ord + = o => o === NOrd.LT ? LT : o === NOrd.EQ ? EQ : GT; + +export const toNOrd: (b: Ord) => NOrd + = o => $$(o._(__(NOrd.LT))._(__(NOrd.EQ))._(__(NOrd.GT))); diff --git a/src/pair.ts b/src/pair.ts index b744e0e..a027da6 100644 --- a/src/pair.ts +++ b/src/pair.ts @@ -1,4 +1,6 @@ import { L, P, _ } from './core'; +import { GT, LT, Ord } from './ord'; +import { Bool, False, True, and } from './bool'; export type Pair = L<(f: L<(f: F) => L<(s: S) => R>>) => R>; @@ -25,3 +27,49 @@ export const both: L<(tf: = _((tf: L<(f: F) => FR>) => _((ts: L<(s: S) => SR>) => _((p: Pair) => p._(_(f => _(s => Pair._(tf._(f))._(ts._(s)))))))); + +export const uncurry: L<(t: L<(f: F) => L<(s: S) => R>>) => L<(p: Pair) => R>> + = _((t: L<(f: F) => L<(s: S) => R>>) => + _((p: Pair) => p._(t))); + +export const cmp: L<(fcmp: L<(l: F) => L<(r: F) => Ord>>) => L<(scmp: L<(l: S) => L<(r: S) => Ord>>) => L<(l: Pair) => L<(r: Pair) => Ord>>>> + = _((fcmp: L<(l: F) => L<(r: F) => Ord>>) => + _((scmp: L<(l: S) => L<(r: S) => Ord>>) => + _((l: Pair) => + _((r: Pair) => + fcmp._(fst._(l))._(fst._(r))._(LT)._(scmp._(snd._(l))._(snd._(r)))._(GT))))); + +export const lt: L<(fcmp: L<(l: F) => L<(r: F) => Ord>>) => L<(scmp: L<(l: S) => L<(r: S) => Bool>>) => L<(l: Pair) => L<(r: Pair) => Bool>>>> + = _((fcmp: L<(l: F) => L<(r: F) => Ord>>) => + _((scmp: L<(l: S) => L<(r: S) => Ord>>) => + _((l: Pair) => + _((r: Pair) => + fcmp._(fst._(l))._(fst._(r))._(True)._(scmp._(snd._(l))._(snd._(r))._(True)._(False)._(False))._(False))))); + +export const le: L<(fcmp: L<(l: F) => L<(r: F) => Ord>>) => L<(scmp: L<(l: S) => L<(r: S) => Bool>>) => L<(l: Pair) => L<(r: Pair) => Bool>>>> += _((fcmp: L<(l: F) => L<(r: F) => Ord>>) => + _((scmp: L<(l: S) => L<(r: S) => Ord>>) => + _((l: Pair) => + _((r: Pair) => + fcmp._(fst._(l))._(fst._(r))._(True)._(scmp._(snd._(l))._(snd._(r))._(True)._(True)._(False))._(False))))); + +export const eq: L<(feq: L<(l: F) => L<(r: F) => Bool>>) => L<(seq: L<(l: S) => L<(r: S) => Bool>>) => L<(l: Pair) => L<(r: Pair) => Bool>>>> + = _((feq: L<(l: F) => L<(r: F) => Bool>>) => + _((seq: L<(l: S) => L<(r: S) => Bool>>) => + _((l: Pair) => + _((r: Pair) => + and._(feq._(fst._(l))._(fst._(r)))._(seq._(snd._(l))._(snd._(r))))))); + +export const ge: L<(fcmp: L<(l: F) => L<(r: F) => Ord>>) => L<(scmp: L<(l: S) => L<(r: S) => Bool>>) => L<(l: Pair) => L<(r: Pair) => Bool>>>> += _((fcmp: L<(l: F) => L<(r: F) => Ord>>) => + _((scmp: L<(l: S) => L<(r: S) => Ord>>) => + _((l: Pair) => + _((r: Pair) => + fcmp._(fst._(l))._(fst._(r))._(False)._(scmp._(snd._(l))._(snd._(r))._(False)._(True)._(True))._(True))))); + +export const gt: L<(fcmp: L<(l: F) => L<(r: F) => Ord>>) => L<(scmp: L<(l: S) => L<(r: S) => Bool>>) => L<(l: Pair) => L<(r: Pair) => Bool>>>> += _((fcmp: L<(l: F) => L<(r: F) => Ord>>) => + _((scmp: L<(l: S) => L<(r: S) => Ord>>) => + _((l: Pair) => + _((r: Pair) => + fcmp._(fst._(l))._(fst._(r))._(False)._(scmp._(snd._(l))._(snd._(r))._(False)._(False)._(True))._(True))))); diff --git a/src/string.ts b/src/string.ts index 3b68304..13159eb 100644 --- a/src/string.ts +++ b/src/string.ts @@ -1,8 +1,9 @@ -import { toNative as $n, L, _, fromNative as _n } from './core'; +import { toNative as $$, L, _, fromNative as __ } from './core'; +import { Ord } from './ord'; import { Bool } from './bool'; import { fromNumber as _nn } from './num'; -import { toChar as $c, Char, fromChar as _c, eq as eqc } from './char'; -import { Cons as ConsL, List, Nil, concat as concatl, eq as eql } from './list'; +import { toChar as $c, Char, fromChar as _c, cmp as cmpc, eq as eqc } from './char'; +import { Cons as ConsL, List, Nil, cmp as cmpl, concat as concatl, eq as eql, ge as gel, gt as gtl, le as lel, lt as ltl } from './list'; export type String = List; @@ -18,11 +19,26 @@ export const cons: L<(c: Char) => L<(s: String) => String>> export const concat: L<(l: String) => L<(r: String) => String>> = concatl; +export const cmp: L<(l: String) => L<(r: String) => Ord>> + = cmpl._(cmpc); + +export const lt: L<(l: String) => L<(r: String) => Bool>> + = ltl._(cmpc); + +export const le: L<(l: String) => L<(r: String) => Bool>> + = lel._(cmpc); + export const eq: L<(l: String) => L<(r: String) => Bool>> = eql._(eqc); +export const ge: L<(l: String) => L<(r: String) => Bool>> + = gel._(cmpc); + +export const gt: L<(l: String) => L<(r: String) => Bool>> + = gtl._(cmpc); + export const fromString: (xs: string) => String = xs => xs.length === 0 ? Nil : Cons._(_c(xs[0]))._(new L(() => fromString(xs.slice(1)).value)); export const toString: (xs: String) => string - = xs => $n(xs._(_n(''))._(_(x => _(xs => _n($c(x) + toString(xs)))))); + = xs => $$(xs._(__(''))._(_(x => _(xs => __($c(x) + toString(xs)))))); diff --git a/test/bool.spec.ts b/test/bool.spec.ts index ce1e127..298e94f 100644 --- a/test/bool.spec.ts +++ b/test/bool.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from '@jest/globals'; import { undef } from '../src/core'; -import { toBoolean as $, False, True, fromBoolean as _, and, eq, iif, not, or, xor } from '../src/bool'; +import { toNOrd as $o, NOrd } from '../src/ord'; +import { toBoolean as $, False, True, fromBoolean as _, and, cmp, eq, ge, gt, iif, le, lt, not, or, xor } from '../src/bool'; describe('Bool', () => { describe('toBoolean', () => { @@ -38,6 +39,60 @@ describe('Bool', () => { }); }); + describe('not', () => { + it('not False is True', () => { + expect($(not._(False))).toBe(true); + }); + + it('not True is False', () => { + expect($(not._(True))).toBe(false); + }); + }); + + describe('lt', () => { + it('False lt False is False', () => { + expect($(lt._(False)._(False))).toBe(false); + }); + + it('False lt True is True', () => { + expect($(lt._(False)._(True))).toBe(true); + }); + + it('True lt False is False', () => { + expect($(lt._(True)._(False))).toBe(false); + }); + + it('True lt True is False', () => { + expect($(lt._(True)._(True))).toBe(false); + }); + + it('True lt ignores second argument', () => { + expect($(lt._(True)._(undef))).toBe(false); + }); + }); + + describe('le', () => { + it('False le False is True', () => { + expect($(le._(False)._(False))).toBe(true); + }); + + it('False le True is True', () => { + expect($(le._(False)._(True))).toBe(true); + }); + + it('True le False is False', () => { + expect($(le._(True)._(False))).toBe(false); + }); + + it('True le True is True', () => { + expect($(le._(True)._(True))).toBe(true); + }); + + it('False le ignores second argument', () => { + expect($(le._(False)._(undef))).toBe(true); + }); + }); + describe('eq', () => { it('False eq False is True', () => { expect($(eq._(False)._(False))).toBe(true); @@ -56,13 +111,65 @@ describe('Bool', () => { }); }); - describe('not', () => { - it('not False is True', () => { - expect($(not._(False))).toBe(true); + describe('ge', () => { + it('False ge False is True', () => { + expect($(ge._(False)._(False))).toBe(true); }); - it('not True is False', () => { - expect($(not._(True))).toBe(false); + it('False ge True is False', () => { + expect($(ge._(False)._(True))).toBe(false); + }); + + it('True ge False is True', () => { + expect($(ge._(True)._(False))).toBe(true); + }); + + it('True ge True is True', () => { + expect($(ge._(True)._(True))).toBe(true); + }); + + it('True ge ignores second argument', () => { + expect($(ge._(True)._(undef))).toBe(true); + }); + }); + + describe('gt', () => { + it('False gt False is False', () => { + expect($(gt._(False)._(False))).toBe(false); + }); + + it('False gt True is False', () => { + expect($(gt._(False)._(True))).toBe(false); + }); + + it('True gt False is True', () => { + expect($(gt._(True)._(False))).toBe(true); + }); + + it('True gt True is False', () => { + expect($(gt._(True)._(True))).toBe(false); + }); + + it('False gt ignores second argument', () => { + expect($(gt._(False)._(undef))).toBe(false); + }); + }); + + describe('cmp', () => { + it('False cmp False is EQ', () => { + expect($o(cmp._(False)._(False))).toBe(NOrd.EQ); + }); + + it('False cmp True is LT', () => { + expect($o(cmp._(False)._(True))).toBe(NOrd.LT); + }); + + it('True cmp False is GT', () => { + expect($o(cmp._(True)._(False))).toBe(NOrd.GT); + }); + + it('True cmp True is EQ', () => { + expect($o(cmp._(True)._(True))).toBe(NOrd.EQ); }); }); diff --git a/test/char.spec.ts b/test/char.spec.ts index dd70d44..8779e59 100644 --- a/test/char.spec.ts +++ b/test/char.spec.ts @@ -1,7 +1,8 @@ import { describe, expect, it } from '@jest/globals'; +import { toNOrd as $o, NOrd } from '../src/ord'; import { toBoolean as $b, fromBoolean as _b } from '../src/bool'; import { fromNumber as _n } from '../src/num'; -import { toChar as $, fromChar as _, eq } from '../src/char'; +import { toChar as $, fromChar as _, cmp, eq, ge, gt, le, lt } from '../src/char'; describe('Char', () => { describe('toChar', () => { @@ -40,6 +41,84 @@ describe('Char', () => { }); }); + describe('cmp', () => { + it('"0" cmp "0" is EQ', () => { + expect($o(cmp._(_('0'))._(_('0')))).toBe(NOrd.EQ); + }); + + it('"0" cmp "a" is LT', () => { + expect($o(cmp._(_('0'))._(_('a')))).toBe(NOrd.LT); + }); + + it('"a" cmp "0" is GT', () => { + expect($o(cmp._(_('a'))._(_('0')))).toBe(NOrd.GT); + }); + + it('"z" cmp "z" is EQ', () => { + expect($o(cmp._(_('z'))._(_('z')))).toBe(NOrd.EQ); + }); + + it('"z" cmp "-" is GT', () => { + expect($o(cmp._(_('z'))._(_('-')))).toBe(NOrd.GT); + }); + + it('"-" cmp "z" is LT', () => { + expect($o(cmp._(_('-'))._(_('z')))).toBe(NOrd.LT); + }); + }); + + describe('lt', () => { + it('"0" lt "0" is False', () => { + expect($b(lt._(_('0'))._(_('0')))).toBe(false); + }); + + it('"0" lt "a" is True', () => { + expect($b(lt._(_('0'))._(_('a')))).toBe(true); + }); + + it('"a" lt "0" is False', () => { + expect($b(lt._(_('a'))._(_('0')))).toBe(false); + }); + + it('"z" lt "z" is False', () => { + expect($b(lt._(_('z'))._(_('z')))).toBe(false); + }); + + it('"z" lt "-" is False', () => { + expect($b(lt._(_('z'))._(_('-')))).toBe(false); + }); + + it('"-" lt "z" is True', () => { + expect($b(lt._(_('-'))._(_('z')))).toBe(true); + }); + }); + + describe('le', () => { + it('"0" le "0" is True', () => { + expect($b(le._(_('0'))._(_('0')))).toBe(true); + }); + + it('"0" le "a" is True', () => { + expect($b(le._(_('0'))._(_('a')))).toBe(true); + }); + + it('"a" le "0" is False', () => { + expect($b(le._(_('a'))._(_('0')))).toBe(false); + }); + + it('"z" le "z" is True', () => { + expect($b(le._(_('z'))._(_('z')))).toBe(true); + }); + + it('"z" le "-" is False', () => { + expect($b(le._(_('z'))._(_('-')))).toBe(false); + }); + + it('"-" le "z" is True', () => { + expect($b(le._(_('-'))._(_('z')))).toBe(true); + }); + }); + describe('eq', () => { it('"0" eq "0" is True', () => { expect($b(eq._(_('0'))._(_('0')))).toBe(true); @@ -49,12 +128,72 @@ describe('Char', () => { expect($b(eq._(_('0'))._(_('a')))).toBe(false); }); - it('"a" eq "a" is True', () => { - expect($b(eq._(_('a'))._(_('a')))).toBe(true); + it('"a" eq "0" is False', () => { + expect($b(eq._(_('a'))._(_('0')))).toBe(false); + }); + + it('"z" eq "z" is True', () => { + expect($b(eq._(_('z'))._(_('z')))).toBe(true); + }); + + it('"z" eq "-" is False', () => { + expect($b(eq._(_('z'))._(_('-')))).toBe(false); + }); + + it('"-" eq "z" is False', () => { + expect($b(eq._(_('-'))._(_('z')))).toBe(false); + }); + }); + + describe('ge', () => { + it('"0" ge "0" is True', () => { + expect($b(ge._(_('0'))._(_('0')))).toBe(true); + }); + + it('"0" ge "a" is False', () => { + expect($b(ge._(_('0'))._(_('a')))).toBe(false); + }); + + it('"a" ge "0" is True', () => { + expect($b(ge._(_('a'))._(_('0')))).toBe(true); + }); + + it('"z" ge "z" is True', () => { + expect($b(ge._(_('z'))._(_('z')))).toBe(true); + }); + + it('"z" ge "-" is True', () => { + expect($b(ge._(_('z'))._(_('-')))).toBe(true); + }); + + it('"-" ge "z" is False', () => { + expect($b(ge._(_('-'))._(_('z')))).toBe(false); + }); + }); + + describe('gt', () => { + it('"0" gt "0" is False', () => { + expect($b(gt._(_('0'))._(_('0')))).toBe(false); + }); + + it('"0" gt "a" is False', () => { + expect($b(gt._(_('0'))._(_('a')))).toBe(false); + }); + + it('"a" gt "0" is True', () => { + expect($b(gt._(_('a'))._(_('0')))).toBe(true); + }); + + it('"z" gt "z" is False', () => { + expect($b(gt._(_('z'))._(_('z')))).toBe(false); + }); + + it('"z" gt "-" is True', () => { + expect($b(gt._(_('z'))._(_('-')))).toBe(true); }); - it('"a" eq "z" is True', () => { - expect($b(eq._(_('a'))._(_('z')))).toBe(false); + it('"-" gt "z" is False', () => { + expect($b(gt._(_('-'))._(_('z')))).toBe(false); }); }); }); diff --git a/test/core.spec.ts b/test/core.spec.ts index a003f30..ad7cdb2 100644 --- a/test/core.spec.ts +++ b/test/core.spec.ts @@ -1,18 +1,18 @@ import { describe, expect, it } from '@jest/globals'; -import { _, cnst, fromNative, id, toNative, undef } from '../src/core'; +import { toNative as $$, _, fromNative as __, cnst, id, undef } from '../src/core'; describe('id', () => { it('returns first argument', () => { - expect(toNative(id._(fromNative('first')))).toBe('first'); + expect($$(id._(__('first')))).toBe('first'); }); }); describe('cnst', () => { it('returns first argument after receiving second', () => { - expect(toNative(cnst._(fromNative('first'))._(fromNative('second')))).toBe('first'); + expect($$(cnst._(__('first'))._(__('second')))).toBe('first'); }); it('ignores second argument', () => { - expect(toNative(cnst._(fromNative('first'))._(undef))).toBe('first'); + expect($$(cnst._(__('first'))._(undef))).toBe('first'); }); }); diff --git a/test/list.spec.ts b/test/list.spec.ts index 8d0346c..1297ebe 100644 --- a/test/list.spec.ts +++ b/test/list.spec.ts @@ -1,13 +1,20 @@ import { describe, expect, it } from '@jest/globals'; -import { L, _, toNative, undef } from '../src/core'; +import { fromNative as $$, L, _, toNative as __, undef } from '../src/core'; +import { toNOrd as $o, NOrd } from '../src/ord'; import { toBoolean as $b, iif } from '../src/bool'; -import { toNumber as $n, Num, Succ, Zero, fromNumber as _n, eq as eqn, even, odd, succ, sum } from '../src/num'; -import { toArray as $a, toNumberArray as $na, Cons, List, Nil, fromArray as _a, fromNumberArray as _na, all, any, concat, cons, eq, filter, foldl, foldlz, foldr, foldrz, head, map, tail } from '../src/list'; +import { toNumber as $n, toNumber as $nn, Num, Succ, Zero, fromNumber as _n, fromNumber as _nn, cmp as cmpn, eq as eqn, even, odd, succ, sum } from '../src/num'; +import { toArray as $a, Cons, List, Nil, fromArray as _a, all, any, cmp, concat, cons, eq, filter, foldl, foldlz, foldr, foldrz, ge, gt, head, le, lt, map, tail } from '../src/list'; describe('List', () => { const iterate: (n: Num) => List = n => new L(() => Cons._(n)._(iterate(Succ._(n))).value); const infinite: List = iterate(Zero); + const _na: (xs: number[]) => List + = xs => xs.length === 0 ? Nil : Cons._(_nn(xs[0]))._(new L(() => _na(xs.slice(1)).value)); + + const $na: (xs: List) => number[] + = xs => __(xs._($$([]))._(_(x => _(xs => $$([$nn(x), ...$na(xs)]))))); + describe('toArray', () => { it('converts []', () => { expect($a(Nil)).toEqual([]); @@ -74,7 +81,7 @@ describe('List', () => { describe('head', () => { it('returns nothing from Nil', () => { - expect(() => toNative(head._(Nil))).toThrow(); + expect(() => __(head._(Nil))).toThrow(); }); it('returns only item', () => { @@ -181,6 +188,123 @@ describe('List', () => { }); }); + describe('cmp', () => { + it('Nil cmp Nil is EQ', () => { + expect($o(cmp._(cmpn)._(_na([]))._(_na([])))).toEqual(NOrd.EQ); + }); + + it('Nil cmp [0, 1, 2] is LT', () => { + expect($o(cmp._(cmpn)._(_na([]))._(_na([0, 1, 2])))).toEqual(NOrd.LT); + }); + + it('[0, 1, 2] cmp Nil is GT', () => { + expect($o(cmp._(cmpn)._(_na([0, 1, 2]))._(_na([])))).toEqual(NOrd.GT); + }); + + it('[0] cmp [0, 1, 2] is LT', () => { + expect($o(cmp._(cmpn)._(_na([0]))._(_na([0, 1, 2])))).toEqual(NOrd.LT); + }); + + it('[0, 1, 2] cmp [0] is GT', () => { + expect($o(cmp._(cmpn)._(_na([0, 1, 2]))._(_na([0])))).toEqual(NOrd.GT); + }); + + it('[1, 2, 0] cmp [0, 1, 2] is GT', () => { + expect($o(cmp._(cmpn)._(_na([1, 2, 0]))._(_na([0, 1, 2])))).toEqual(NOrd.GT); + }); + + it('[0, 1, 2] cmp [1, 2, 0] is LT', () => { + expect($o(cmp._(cmpn)._(_na([0, 1, 2]))._(_na([1, 2, 0])))).toEqual(NOrd.LT); + }); + + it('[0, 1, 2] cmp [0, 1, 2] is EQ', () => { + expect($o(cmp._(cmpn)._(_na([0, 1, 2]))._(_na([0, 1, 2])))).toEqual(NOrd.EQ); + }); + + it('handles infinite lists', () => { + expect($o(cmp._(cmpn)._(_na([0, 1, 2]))._(infinite))).toEqual(NOrd.LT); + expect($o(cmp._(cmpn)._(infinite)._(_na([0, 1, 2])))).toEqual(NOrd.GT); + }); + }); + + describe('lt', () => { + it('Nil lt Nil is False', () => { + expect($b(lt._(cmpn)._(_na([]))._(_na([])))).toEqual(false); + }); + + it('Nil lt [0, 1, 2] is True', () => { + expect($b(lt._(cmpn)._(_na([]))._(_na([0, 1, 2])))).toEqual(true); + }); + + it('[0, 1, 2] lt Nil is False', () => { + expect($b(lt._(cmpn)._(_na([0, 1, 2]))._(_na([])))).toEqual(false); + }); + + it('[0] lt [0, 1, 2] is True', () => { + expect($b(lt._(cmpn)._(_na([0]))._(_na([0, 1, 2])))).toEqual(true); + }); + + it('[0, 1, 2] lt [0] is False', () => { + expect($b(lt._(cmpn)._(_na([0, 1, 2]))._(_na([0])))).toEqual(false); + }); + + it('[1, 2, 0] lt [0, 1, 2] is False', () => { + expect($b(lt._(cmpn)._(_na([1, 2, 0]))._(_na([0, 1, 2])))).toEqual(false); + }); + + it('[0, 1, 2] lt [1, 2, 0] is True', () => { + expect($b(lt._(cmpn)._(_na([0, 1, 2]))._(_na([1, 2, 0])))).toEqual(true); + }); + + it('[0, 1, 2] lt [0, 1, 2] is False', () => { + expect($b(lt._(cmpn)._(_na([0, 1, 2]))._(_na([0, 1, 2])))).toEqual(false); + }); + + it('handles infinite lists', () => { + expect($b(lt._(cmpn)._(_na([0, 1, 2]))._(infinite))).toEqual(true); + expect($b(lt._(cmpn)._(infinite)._(_na([0, 1, 2])))).toEqual(false); + }); + }); + + describe('le', () => { + it('Nil le Nil is True', () => { + expect($b(le._(cmpn)._(_na([]))._(_na([])))).toEqual(true); + }); + + it('Nil le [0, 1, 2] is True', () => { + expect($b(le._(cmpn)._(_na([]))._(_na([0, 1, 2])))).toEqual(true); + }); + + it('[0, 1, 2] le Nil is False', () => { + expect($b(le._(cmpn)._(_na([0, 1, 2]))._(_na([])))).toEqual(false); + }); + + it('[0] le [0, 1, 2] is True', () => { + expect($b(le._(cmpn)._(_na([0]))._(_na([0, 1, 2])))).toEqual(true); + }); + + it('[0, 1, 2] le [0] is False', () => { + expect($b(le._(cmpn)._(_na([0, 1, 2]))._(_na([0])))).toEqual(false); + }); + + it('[1, 2, 0] le [0, 1, 2] is False', () => { + expect($b(le._(cmpn)._(_na([1, 2, 0]))._(_na([0, 1, 2])))).toEqual(false); + }); + + it('[0, 1, 2] le [1, 2, 0] is True', () => { + expect($b(le._(cmpn)._(_na([0, 1, 2]))._(_na([1, 2, 0])))).toEqual(true); + }); + + it('[0, 1, 2] le [0, 1, 2] is True', () => { + expect($b(le._(cmpn)._(_na([0, 1, 2]))._(_na([0, 1, 2])))).toEqual(true); + }); + + it('handles infinite lists', () => { + expect($b(le._(cmpn)._(_na([0, 1, 2]))._(infinite))).toEqual(true); + expect($b(le._(cmpn)._(infinite)._(_na([0, 1, 2])))).toEqual(false); + }); + }); + describe('eq', () => { it('Nil eq Nil is True', () => { expect($b(eq._(eqn)._(_na([]))._(_na([])))).toEqual(true); @@ -216,6 +340,85 @@ describe('List', () => { it('handles infinite lists', () => { expect($b(eq._(eqn)._(_na([0, 1, 2]))._(infinite))).toEqual(false); + expect($b(eq._(eqn)._(infinite)._(_na([0, 1, 2])))).toEqual(false); + }); + }); + + describe('ge', () => { + it('Nil ge Nil is True', () => { + expect($b(ge._(cmpn)._(_na([]))._(_na([])))).toEqual(true); + }); + + it('Nil ge [0, 1, 2] is False', () => { + expect($b(ge._(cmpn)._(_na([]))._(_na([0, 1, 2])))).toEqual(false); + }); + + it('[0, 1, 2] ge Nil is True', () => { + expect($b(ge._(cmpn)._(_na([0, 1, 2]))._(_na([])))).toEqual(true); + }); + + it('[0] ge [0, 1, 2] is False', () => { + expect($b(ge._(cmpn)._(_na([0]))._(_na([0, 1, 2])))).toEqual(false); + }); + + it('[0, 1, 2] ge [0] is True', () => { + expect($b(ge._(cmpn)._(_na([0, 1, 2]))._(_na([0])))).toEqual(true); + }); + + it('[1, 2, 0] ge [0, 1, 2] is True', () => { + expect($b(ge._(cmpn)._(_na([1, 2, 0]))._(_na([0, 1, 2])))).toEqual(true); + }); + + it('[0, 1, 2] ge [1, 2, 0] is False', () => { + expect($b(ge._(cmpn)._(_na([0, 1, 2]))._(_na([1, 2, 0])))).toEqual(false); + }); + + it('[0, 1, 2] ge [0, 1, 2] is True', () => { + expect($b(ge._(cmpn)._(_na([0, 1, 2]))._(_na([0, 1, 2])))).toEqual(true); + }); + + it('handles infinite lists', () => { + expect($b(ge._(cmpn)._(_na([0, 1, 2]))._(infinite))).toEqual(false); + expect($b(ge._(cmpn)._(infinite)._(_na([0, 1, 2])))).toEqual(true); + }); + }); + + describe('gt', () => { + it('Nil gt Nil is False', () => { + expect($b(gt._(cmpn)._(_na([]))._(_na([])))).toEqual(false); + }); + + it('Nil gt [0, 1, 2] is False', () => { + expect($b(gt._(cmpn)._(_na([]))._(_na([0, 1, 2])))).toEqual(false); + }); + + it('[0, 1, 2] gt Nil is True', () => { + expect($b(gt._(cmpn)._(_na([0, 1, 2]))._(_na([])))).toEqual(true); + }); + + it('[0] gt [0, 1, 2] is False', () => { + expect($b(gt._(cmpn)._(_na([0]))._(_na([0, 1, 2])))).toEqual(false); + }); + + it('[0, 1, 2] gt [0] is True', () => { + expect($b(gt._(cmpn)._(_na([0, 1, 2]))._(_na([0])))).toEqual(true); + }); + + it('[1, 2, 0] gt [0, 1, 2] is True', () => { + expect($b(gt._(cmpn)._(_na([1, 2, 0]))._(_na([0, 1, 2])))).toEqual(true); + }); + + it('[0, 1, 2] gt [1, 2, 0] is False', () => { + expect($b(gt._(cmpn)._(_na([0, 1, 2]))._(_na([1, 2, 0])))).toEqual(false); + }); + + it('[0, 1, 2] gt [0, 1, 2] is False', () => { + expect($b(gt._(cmpn)._(_na([0, 1, 2]))._(_na([0, 1, 2])))).toEqual(false); + }); + + it('handles infinite lists', () => { + expect($b(gt._(cmpn)._(_na([0, 1, 2]))._(infinite))).toEqual(false); + expect($b(gt._(cmpn)._(infinite)._(_na([0, 1, 2])))).toEqual(true); }); }); diff --git a/test/num.spec.ts b/test/num.spec.ts index 2c149aa..fbb4c96 100644 --- a/test/num.spec.ts +++ b/test/num.spec.ts @@ -1,7 +1,8 @@ import { describe, expect, it } from '@jest/globals'; import { L, undef } from '../src/core'; +import { toNOrd as $o, NOrd } from '../src/ord'; import { toBoolean as $b, fromBoolean as _b } from '../src/bool'; -import { toNumber as $, Num, Succ, Zero, fromNumber as _, eq, ifz, mul, pred, sub, succ, sum } from '../src/num'; +import { toNumber as $, Num, Succ, Zero, fromNumber as _, cmp, eq, ge, gt, ifz, le, lt, mul, pred, sub, succ, sum } from '../src/num'; describe('Num', () => { const infinity: Num = new L(() => Succ._(infinity).value); @@ -80,6 +81,99 @@ describe('Num', () => { }); }); + describe('cmp', () => { + it('0 cmp 0 is EQ', () => { + expect($o(cmp._(_(0))._(_(0)))).toBe(NOrd.EQ); + }); + + it('0 cmp 1 is LT', () => { + expect($o(cmp._(_(0))._(_(1)))).toBe(NOrd.LT); + }); + + it('1 cmp 0 is GT', () => { + expect($o(cmp._(_(1))._(_(0)))).toBe(NOrd.GT); + }); + + it('3 cmp 3 is EQ', () => { + expect($o(cmp._(_(3))._(_(3)))).toBe(NOrd.EQ); + }); + + it('3 cmp 7 is LT', () => { + expect($o(cmp._(_(3))._(_(7)))).toBe(NOrd.LT); + }); + + it('7 cmp 3 is GT', () => { + expect($o(cmp._(_(7))._(_(3)))).toBe(NOrd.GT); + }); + + it('handles infinity', () => { + expect($o(cmp._(_(7))._(infinity))).toBe(NOrd.LT); + expect($o(cmp._(infinity)._(_(7)))).toBe(NOrd.GT); + }); + }); + + describe('lt', () => { + it('0 lt 0 is False', () => { + expect($b(lt._(_(0))._(_(0)))).toBe(false); + }); + + it('0 lt 1 is True', () => { + expect($b(lt._(_(0))._(_(1)))).toBe(true); + }); + + it('1 lt 0 is False', () => { + expect($b(lt._(_(1))._(_(0)))).toBe(false); + }); + + it('3 lt 3 is False', () => { + expect($b(lt._(_(3))._(_(3)))).toBe(false); + }); + + it('3 lt 7 is True', () => { + expect($b(lt._(_(3))._(_(7)))).toBe(true); + }); + + it('7 lt 3 is False', () => { + expect($b(lt._(_(7))._(_(3)))).toBe(false); + }); + + it('handles infinity', () => { + expect($b(lt._(_(7))._(infinity))).toBe(true); + expect($b(lt._(infinity)._(_(7)))).toBe(false); + }); + }); + + describe('le', () => { + it('0 le 0 is True', () => { + expect($b(le._(_(0))._(_(0)))).toBe(true); + }); + + it('0 le 1 is True', () => { + expect($b(le._(_(0))._(_(1)))).toBe(true); + }); + + it('1 le 0 is False', () => { + expect($b(le._(_(1))._(_(0)))).toBe(false); + }); + + it('3 le 3 is True', () => { + expect($b(le._(_(3))._(_(3)))).toBe(true); + }); + + it('3 le 7 is True', () => { + expect($b(le._(_(3))._(_(7)))).toBe(true); + }); + + it('7 le 3 is False', () => { + expect($b(le._(_(7))._(_(3)))).toBe(false); + }); + + it('handles infinity', () => { + expect($b(le._(_(7))._(infinity))).toBe(true); + expect($b(le._(infinity)._(_(7)))).toBe(false); + }); + }); + describe('eq', () => { it('0 eq 0 is True', () => { expect($b(eq._(_(0))._(_(0)))).toBe(true); @@ -107,6 +201,69 @@ describe('Num', () => { it('handles infinity', () => { expect($b(eq._(_(7))._(infinity))).toBe(false); + expect($b(eq._(infinity)._(_(7)))).toBe(false); + }); + }); + + describe('ge', () => { + it('0 ge 0 is True', () => { + expect($b(ge._(_(0))._(_(0)))).toBe(true); + }); + + it('0 ge 1 is False', () => { + expect($b(ge._(_(0))._(_(1)))).toBe(false); + }); + + it('1 ge 0 is True', () => { + expect($b(ge._(_(1))._(_(0)))).toBe(true); + }); + + it('3 ge 3 is True', () => { + expect($b(ge._(_(3))._(_(3)))).toBe(true); + }); + + it('3 ge 7 is False', () => { + expect($b(ge._(_(3))._(_(7)))).toBe(false); + }); + + it('7 ge 3 is True', () => { + expect($b(ge._(_(7))._(_(3)))).toBe(true); + }); + + it('handles infinity', () => { + expect($b(ge._(_(7))._(infinity))).toBe(false); + expect($b(ge._(infinity)._(_(7)))).toBe(true); + }); + }); + + describe('gt', () => { + it('0 gt 0 is False', () => { + expect($b(gt._(_(0))._(_(0)))).toBe(false); + }); + + it('0 gt 1 is False', () => { + expect($b(gt._(_(0))._(_(1)))).toBe(false); + }); + + it('1 gt 0 is True', () => { + expect($b(gt._(_(1))._(_(0)))).toBe(true); + }); + + it('3 gt 3 is False', () => { + expect($b(gt._(_(3))._(_(3)))).toBe(false); + }); + + it('3 gt 7 is False', () => { + expect($b(gt._(_(3))._(_(7)))).toBe(false); + }); + + it('7 gt 3 is True', () => { + expect($b(gt._(_(7))._(_(3)))).toBe(true); + }); + + it('handles infinity', () => { + expect($b(gt._(_(7))._(infinity))).toBe(false); + expect($b(gt._(infinity)._(_(7)))).toBe(true); }); }); diff --git a/test/pair.spec.ts b/test/pair.spec.ts index c926b3e..4a2f4ca 100644 --- a/test/pair.spec.ts +++ b/test/pair.spec.ts @@ -1,8 +1,9 @@ import { describe, expect, it } from '@jest/globals'; import { undef } from '../src/core'; -import { toBoolean as $b, fromBoolean as _b, not } from '../src/bool'; -import { toNumber as $n, fromNumber as _n, succ } from '../src/num'; -import { Pair, both, first, fst, second, snd } from '../src/pair'; +import { toNOrd as $o, NOrd } from '../src/ord'; +import { toBoolean as $b, fromBoolean as _b, cmp as bcmp, eq as beq, not } from '../src/bool'; +import { toNumber as $n, fromNumber as _n, cmp as ncmp, eq as neq, succ } from '../src/num'; +import { Pair, both, cmp, eq, first, fst, ge, gt, le, lt, second, snd } from '../src/pair'; describe('Pair', () => { describe('fst', () => { @@ -51,4 +52,160 @@ describe('Pair', () => { expect($n(snd._(both._(not)._(succ)._(Pair._(_b(false))._(_n(0)))))).toBe(1); }); }); + + describe('cmp', () => { + it('(False, 0) cmp (False, 0) is EQ', () => { + expect($o(cmp._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(false))._(_n(0))))).toBe(NOrd.EQ); + }); + + it('(False, 0) cmp (False, 1) is LT', () => { + expect($o(cmp._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(false))._(_n(1))))).toBe(NOrd.LT); + }); + + it('(False, 1) cmp (False, 0) is GT', () => { + expect($o(cmp._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(1)))._(Pair._(_b(false))._(_n(0))))).toBe(NOrd.GT); + }); + + it('(False, 0) cmp (True, 0) is LT', () => { + expect($o(cmp._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(true))._(_n(0))))).toBe(NOrd.LT); + }); + + it('(True, 0) cmp (False, 0) is GT', () => { + expect($o(cmp._(bcmp)._(ncmp)._(Pair._(_b(true))._(_n(0)))._(Pair._(_b(false))._(_n(0))))).toBe(NOrd.GT); + }); + + it('ignores second if first not equal', () => { + expect($o(cmp._(bcmp)._(undef)._(Pair._(_b(false))._(undef))._(Pair._(_b(true))._(undef)))).toBe(NOrd.LT); + }); + }); + + describe('lt', () => { + it('(False, 0) lt (False, 0) is False', () => { + expect($b(lt._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(false))._(_n(0))))).toBe(false); + }); + + it('(False, 0) lt (False, 1) is True', () => { + expect($b(lt._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(false))._(_n(1))))).toBe(true); + }); + + it('(False, 1) lt (False, 0) is False', () => { + expect($b(lt._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(1)))._(Pair._(_b(false))._(_n(0))))).toBe(false); + }); + + it('(False, 0) lt (True, 0) is True', () => { + expect($b(lt._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(true))._(_n(0))))).toBe(true); + }); + + it('(True, 0) lt (False, 0) is False', () => { + expect($b(lt._(bcmp)._(ncmp)._(Pair._(_b(true))._(_n(0)))._(Pair._(_b(false))._(_n(0))))).toBe(false); + }); + + it('ignores second if first not equal', () => { + expect($b(lt._(bcmp)._(undef)._(Pair._(_b(false))._(undef))._(Pair._(_b(true))._(undef)))).toBe(true); + }); + }); + + describe('le', () => { + it('(False, 0) le (False, 0) is True', () => { + expect($b(le._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(false))._(_n(0))))).toBe(true); + }); + + it('(False, 0) le (False, 1) is True', () => { + expect($b(le._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(false))._(_n(1))))).toBe(true); + }); + + it('(False, 1) le (False, 0) is False', () => { + expect($b(le._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(1)))._(Pair._(_b(false))._(_n(0))))).toBe(false); + }); + + it('(False, 0) le (True, 0) is True', () => { + expect($b(le._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(true))._(_n(0))))).toBe(true); + }); + + it('(True, 0) le (False, 0) is False', () => { + expect($b(le._(bcmp)._(ncmp)._(Pair._(_b(true))._(_n(0)))._(Pair._(_b(false))._(_n(0))))).toBe(false); + }); + + it('ignores second if first not equal', () => { + expect($b(le._(bcmp)._(undef)._(Pair._(_b(false))._(undef))._(Pair._(_b(true))._(undef)))).toBe(true); + }); + }); + + describe('eq', () => { + it('(False, 0) eq (False, 0) is True', () => { + expect($b(eq._(beq)._(neq)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(false))._(_n(0))))).toBe(true); + }); + + it('(False, 0) eq (False, 1) is False', () => { + expect($b(eq._(beq)._(neq)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(false))._(_n(1))))).toBe(false); + }); + + it('(False, 1) eq (False, 0) is False', () => { + expect($b(eq._(beq)._(neq)._(Pair._(_b(false))._(_n(1)))._(Pair._(_b(false))._(_n(0))))).toBe(false); + }); + + it('(False, 0) eq (True, 0) is True', () => { + expect($b(eq._(beq)._(neq)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(true))._(_n(0))))).toBe(false); + }); + + it('(True, 0) eq (False, 0) is True', () => { + expect($b(eq._(beq)._(neq)._(Pair._(_b(true))._(_n(0)))._(Pair._(_b(false))._(_n(0))))).toBe(false); + }); + + it('ignores second if first not equal', () => { + expect($b(eq._(beq)._(undef)._(Pair._(_b(false))._(undef))._(Pair._(_b(true))._(undef)))).toBe(false); + }); + }); + + describe('ge', () => { + it('(False, 0) ge (False, 0) is True', () => { + expect($b(ge._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(false))._(_n(0))))).toBe(true); + }); + + it('(False, 0) ge (False, 1) is False', () => { + expect($b(ge._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(false))._(_n(1))))).toBe(false); + }); + + it('(False, 1) ge (False, 0) is True', () => { + expect($b(ge._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(1)))._(Pair._(_b(false))._(_n(0))))).toBe(true); + }); + + it('(False, 0) ge (True, 0) is False', () => { + expect($b(ge._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(true))._(_n(0))))).toBe(false); + }); + + it('(True, 0) ge (False, 0) is True', () => { + expect($b(ge._(bcmp)._(ncmp)._(Pair._(_b(true))._(_n(0)))._(Pair._(_b(false))._(_n(0))))).toBe(true); + }); + + it('ignores second if first not equal', () => { + expect($b(ge._(bcmp)._(undef)._(Pair._(_b(false))._(undef))._(Pair._(_b(true))._(undef)))).toBe(false); + }); + }); + + describe('gt', () => { + it('(False, 0) gt (False, 0) is False', () => { + expect($b(gt._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(false))._(_n(0))))).toBe(false); + }); + + it('(False, 0) gt (False, 1) is False', () => { + expect($b(gt._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(false))._(_n(1))))).toBe(false); + }); + + it('(False, 1) gt (False, 0) is True', () => { + expect($b(gt._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(1)))._(Pair._(_b(false))._(_n(0))))).toBe(true); + }); + + it('(False, 0) gt (True, 0) is False', () => { + expect($b(gt._(bcmp)._(ncmp)._(Pair._(_b(false))._(_n(0)))._(Pair._(_b(true))._(_n(0))))).toBe(false); + }); + + it('(True, 0) gt (False, 0) is True', () => { + expect($b(gt._(bcmp)._(ncmp)._(Pair._(_b(true))._(_n(0)))._(Pair._(_b(false))._(_n(0))))).toBe(true); + }); + + it('ignores second if first not equal', () => { + expect($b(gt._(bcmp)._(undef)._(Pair._(_b(false))._(undef))._(Pair._(_b(true))._(undef)))).toBe(false); + }); + }); }); diff --git a/test/string.spec.ts b/test/string.spec.ts index c5337eb..b82dabc 100644 --- a/test/string.spec.ts +++ b/test/string.spec.ts @@ -1,8 +1,9 @@ import { describe, expect, it } from '@jest/globals'; import { L, _, undef } from '../src/core'; +import { NOrd, toNOrd } from '../src/ord'; import { toBoolean as $b } from '../src/bool'; import { toChar as $c, fromChar as _c } from '../src/char'; -import { toString as $s, Cons, Empty, String, fromString as _s, concat, eq } from '../src/string'; +import { toString as $s, Cons, Empty, String, fromString as _s, cmp, concat, eq, ge, gt, le, lt } from '../src/string'; describe('String', () => { const infinite: String = new L(() => Cons._(_c('a'))._(infinite).value); ; @@ -53,41 +54,237 @@ describe('String', () => { }); }); + describe('cmp', () => { + it('"" cmp "" is EQ', () => { + expect(toNOrd(cmp._(_s(''))._(_s('')))).toEqual(NOrd.EQ); + }); + + it('"" cmp "abc" is LT', () => { + expect(toNOrd(cmp._(_s(''))._(_s('abc')))).toEqual(NOrd.LT); + }); + + it('"abc" cmp "" is GT', () => { + expect(toNOrd(cmp._(_s('abc'))._(_s('')))).toEqual(NOrd.GT); + }); + + it('"a" cmp "abc" is LT', () => { + expect(toNOrd(cmp._(_s('a'))._(_s('abc')))).toEqual(NOrd.LT); + }); + + it('"abc" cmp "a" is GT', () => { + expect(toNOrd(cmp._(_s('abc'))._(_s('a')))).toEqual(NOrd.GT); + }); + + it('"bca" cmp "abc" is GT', () => { + expect(toNOrd(cmp._(_s('bca'))._(_s('abc')))).toEqual(NOrd.GT); + }); + + it('"abc" cmp "bca" is LT', () => { + expect(toNOrd(cmp._(_s('abc'))._(_s('bca')))).toEqual(NOrd.LT); + }); + + it('"abc" cmp "abc" is EQ', () => { + expect(toNOrd(cmp._(_s('abc'))._(_s('abc')))).toEqual(NOrd.EQ); + }); + + it('handles infinite strings', () => { + expect(toNOrd(cmp._(_s('abc'))._(infinite))).toEqual(NOrd.GT); + expect(toNOrd(cmp._(infinite)._(_s('abc')))).toEqual(NOrd.LT); + }); + }); + + describe('lt', () => { + it('"" lt "" is False', () => { + expect($b(lt._(_s(''))._(_s('')))).toEqual(false); + }); + + it('"" lt "abc" is True', () => { + expect($b(lt._(_s(''))._(_s('abc')))).toEqual(true); + }); + + it('"abc" lt "" is False', () => { + expect($b(lt._(_s('abc'))._(_s('')))).toEqual(false); + }); + + it('"a" lt "abc" is True', () => { + expect($b(lt._(_s('a'))._(_s('abc')))).toEqual(true); + }); + + it('"abc" lt "a" is False', () => { + expect($b(lt._(_s('abc'))._(_s('a')))).toEqual(false); + }); + + it('"bca" lt "abc" is False', () => { + expect($b(lt._(_s('bca'))._(_s('abc')))).toEqual(false); + }); + + it('"abc" lt "bca" is True', () => { + expect($b(lt._(_s('abc'))._(_s('bca')))).toEqual(true); + }); + + it('"abc" lt "abc" is False', () => { + expect($b(lt._(_s('abc'))._(_s('abc')))).toEqual(false); + }); + + it('handles infinite strings', () => { + expect($b(lt._(_s('abc'))._(infinite))).toEqual(false); + expect($b(lt._(infinite)._(_s('abc')))).toEqual(true); + }); + }); + + describe('le', () => { + it('"" le "" is True', () => { + expect($b(le._(_s(''))._(_s('')))).toEqual(true); + }); + + it('"" le "abc" is True', () => { + expect($b(le._(_s(''))._(_s('abc')))).toEqual(true); + }); + + it('"abc" le "" is False', () => { + expect($b(le._(_s('abc'))._(_s('')))).toEqual(false); + }); + + it('"a" le "abc" is True', () => { + expect($b(le._(_s('a'))._(_s('abc')))).toEqual(true); + }); + + it('"abc" le "a" is False', () => { + expect($b(le._(_s('abc'))._(_s('a')))).toEqual(false); + }); + + it('"bca" le "abc" is False', () => { + expect($b(le._(_s('bca'))._(_s('abc')))).toEqual(false); + }); + + it('"abc" le "bca" is True', () => { + expect($b(le._(_s('abc'))._(_s('bca')))).toEqual(true); + }); + + it('"abc" le "abc" is True', () => { + expect($b(le._(_s('abc'))._(_s('abc')))).toEqual(true); + }); + + it('handles infinite strings', () => { + expect($b(le._(_s('abc'))._(infinite))).toEqual(false); + expect($b(le._(infinite)._(_s('abc')))).toEqual(true); + }); + }); + describe('eq', () => { it('"" eq "" is True', () => { - expect($b(eq._(_s(''))._(_s('')))).toBe(true); + expect($b(eq._(_s(''))._(_s('')))).toEqual(true); }); it('"" eq "abc" is False', () => { - expect($b(eq._(_s(''))._(_s('abc')))).toBe(false); + expect($b(eq._(_s(''))._(_s('abc')))).toEqual(false); }); it('"abc" eq "" is False', () => { - expect($b(eq._(_s('abc'))._(_s('')))).toBe(false); + expect($b(eq._(_s('abc'))._(_s('')))).toEqual(false); }); it('"a" eq "abc" is False', () => { - expect($b(eq._(_s('a'))._(_s('abc')))).toBe(false); + expect($b(eq._(_s('a'))._(_s('abc')))).toEqual(false); }); it('"abc" eq "a" is False', () => { - expect($b(eq._(_s('abc'))._(_s('a')))).toBe(false); + expect($b(eq._(_s('abc'))._(_s('a')))).toEqual(false); }); it('"bca" eq "abc" is False', () => { - expect($b(eq._(_s('bca'))._(_s('abc')))).toBe(false); + expect($b(eq._(_s('bca'))._(_s('abc')))).toEqual(false); }); it('"abc" eq "bca" is False', () => { - expect($b(eq._(_s('abc'))._(_s('bca')))).toBe(false); + expect($b(eq._(_s('abc'))._(_s('bca')))).toEqual(false); }); it('"abc" eq "abc" is True', () => { - expect($b(eq._(_s('abc'))._(_s('abc')))).toBe(true); + expect($b(eq._(_s('abc'))._(_s('abc')))).toEqual(true); + }); + + it('handles infinite strings', () => { + expect($b(eq._(_s('abc'))._(infinite))).toEqual(false); + expect($b(eq._(infinite)._(_s('abc')))).toEqual(false); + }); + }); + + describe('ge', () => { + it('"" ge "" is True', () => { + expect($b(ge._(_s(''))._(_s('')))).toEqual(true); + }); + + it('"" ge "abc" is False', () => { + expect($b(ge._(_s(''))._(_s('abc')))).toEqual(false); + }); + + it('"abc" ge "" is True', () => { + expect($b(ge._(_s('abc'))._(_s('')))).toEqual(true); + }); + + it('"a" ge "abc" is False', () => { + expect($b(ge._(_s('a'))._(_s('abc')))).toEqual(false); + }); + + it('"abc" ge "a" is True', () => { + expect($b(ge._(_s('abc'))._(_s('a')))).toEqual(true); + }); + + it('"bca" ge "abc" is True', () => { + expect($b(ge._(_s('bca'))._(_s('abc')))).toEqual(true); + }); + + it('"abc" ge "bca" is False', () => { + expect($b(ge._(_s('abc'))._(_s('bca')))).toEqual(false); + }); + + it('"abc" ge "abc" is True', () => { + expect($b(ge._(_s('abc'))._(_s('abc')))).toEqual(true); + }); + + it('handles infinite strings', () => { + expect($b(ge._(_s('abc'))._(infinite))).toEqual(true); + expect($b(ge._(infinite)._(_s('abc')))).toEqual(false); + }); + }); + + describe('gt', () => { + it('"" gt "" is False', () => { + expect($b(gt._(_s(''))._(_s('')))).toEqual(false); + }); + + it('"" gt "abc" is False', () => { + expect($b(gt._(_s(''))._(_s('abc')))).toEqual(false); + }); + + it('"abc" gt "" is True', () => { + expect($b(gt._(_s('abc'))._(_s('')))).toEqual(true); + }); + + it('"a" gt "abc" is False', () => { + expect($b(gt._(_s('a'))._(_s('abc')))).toEqual(false); + }); + + it('"abc" gt "a" is True', () => { + expect($b(gt._(_s('abc'))._(_s('a')))).toEqual(true); + }); + + it('"bca" gt "abc" is True', () => { + expect($b(gt._(_s('bca'))._(_s('abc')))).toEqual(true); + }); + + it('"abc" gt "bca" is False', () => { + expect($b(gt._(_s('abc'))._(_s('bca')))).toEqual(false); + }); + + it('"abc" gt "abc" is False', () => { + expect($b(gt._(_s('abc'))._(_s('abc')))).toEqual(false); }); it('handles infinite strings', () => { - expect($b(eq._(_s('abc'))._(infinite))).toBe(false); + expect($b(gt._(_s('abc'))._(infinite))).toEqual(true); + expect($b(gt._(infinite)._(_s('abc')))).toEqual(false); }); }); });