More library functions
This commit is contained in:
@@ -11,6 +11,9 @@ export const False: Bool
|
||||
export const iif: L<<T extends P>(b: Bool) => L<(t: T) => L<(f: T) => T>>>
|
||||
= _(b => _(t => _(f => b._(t)._(f))));
|
||||
|
||||
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));
|
||||
|
||||
|
||||
+19
-1
@@ -1,6 +1,6 @@
|
||||
import { L, P, _, fromNative, toNative, undef } from './core';
|
||||
import { Num, fromNumber, toNumber } from './num';
|
||||
import { Bool, iif } from './bool';
|
||||
import { Bool, False, True, and, iif, or } from './bool';
|
||||
|
||||
export type List<T extends P> = L<<R extends P>(z: R) => L<(f: L<(x: T) => L<(xs: List<T>) => R>>) => R>>;
|
||||
|
||||
@@ -42,6 +42,14 @@ export const foldr: L<<T extends P, R extends P>(f: L<(x: T) => L<(a: R) => R>>)
|
||||
export const foldrz: L<<T extends P>(f: L<(x: T) => L<(a: T) => T>>) => L<(xs: List<T>) => T>>
|
||||
= _(_f => _(_z => undef));
|
||||
|
||||
export const eq: L<<T extends P>(e: L<(l: T) =>L <(r: T) => Bool>>) => L<(l: List<T>)=> L<(r: List<T>) => Bool>>>
|
||||
=
|
||||
_(<T extends P>(e: L<(l: T) => L<(r: T) => Bool>>) =>
|
||||
_((l: List<T>) =>
|
||||
_((r: List<T>) => l
|
||||
._(r._(True)._(_(_x => _(_xs => False))))
|
||||
._(_(lx => _(lxs => r._(False)._(_(rx => _(rxs => and._(e._(lx)._(rx))._(eq._(e)._(lxs)._(rxs)))))))))));
|
||||
|
||||
export const map: L<<T extends P, R extends P>(f: L<(x: T) => R>) => L<(xs: List<T>) => List<R>>>
|
||||
=
|
||||
_(<T extends P, R extends P>(f: L<(x: T) => R>) =>
|
||||
@@ -52,6 +60,16 @@ export const filter: L<<T extends P>(f: L<(x: T) => Bool>) => L<(xs: List<T>) =>
|
||||
_(<T extends P>(f: L<(x: T) => Bool>) =>
|
||||
_((xs: List<T>) => xs._(Nil)._(_(x => _(xs => iif._(f._(x))._(Cons._(x)._(filter._(f)._(xs)))._(filter._(f)._(xs)))))));
|
||||
|
||||
export const any: L<<T extends P>(f: L<(x: T) => Bool>) => L<(xs: List<T>) => Bool>>
|
||||
=
|
||||
_(<T extends P>(f: L<(x: T) => Bool>) =>
|
||||
_((xs: List<T>) => xs._(False)._(_(x => _(xs => or._(f._(x))._(any._(f)._(xs)))))));
|
||||
|
||||
export const all: L<<T extends P>(f: L<(x: T) => Bool>) => L<(xs: List<T>) => Bool>>
|
||||
=
|
||||
_(<T extends P>(f: L<(x: T) => Bool>) =>
|
||||
_((xs: List<T>) => xs._(True)._(_(x => _(xs => and._(f._(x))._(all._(f)._(xs)))))));
|
||||
|
||||
export const fromArray: <T extends P>(xs: T[]) => List<T>
|
||||
= xs => xs.length === 0 ? Nil : Cons._(xs[0])._(new L(() => fromArray(xs.slice(1)).value));
|
||||
|
||||
|
||||
@@ -18,6 +18,11 @@ export const succ: L<(n: Num) => Num>
|
||||
export const pred: L<(n: Num) => Num>
|
||||
= _(n => n._(Zero)._(id));
|
||||
|
||||
export const eq: L<(l: Num) => L<(r: Num) => Bool>>
|
||||
= _(l => _(r => l
|
||||
._(r._(True)._(_(_ => False)))
|
||||
._(_(pl => r._(False)._(_(pr => eq._(pl)._(pr)))))));
|
||||
|
||||
export const even: L<(n: Num) => Bool>
|
||||
= _(n => n._(True)._(odd));
|
||||
|
||||
|
||||
+23
-1
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from '@jest/globals';
|
||||
import { toBoolean as $, False, True, fromBoolean as _, and, iif, not, or, xor } from '../src/bool';
|
||||
import { toBoolean as $, False, True, fromBoolean as _, and, eq, iif, not, or, xor } from '../src/bool';
|
||||
|
||||
describe('Bool', () => {
|
||||
describe('toBoolean', () => {
|
||||
@@ -34,6 +34,28 @@ describe('Bool', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('eq', () => {
|
||||
it('False eq False is True', () => {
|
||||
expect(eq).toDeferEvaluationOf(False, False);
|
||||
expect($(eq._(False)._(False))).toBe(true);
|
||||
});
|
||||
|
||||
it('False eq True is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(False, True);
|
||||
expect($(eq._(False)._(True))).toBe(false);
|
||||
});
|
||||
|
||||
it('True eq False is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(True, False);
|
||||
expect($(eq._(True)._(False))).toBe(false);
|
||||
});
|
||||
|
||||
it('True eq True is True', () => {
|
||||
expect(eq).toDeferEvaluationOf(True, True);
|
||||
expect($(eq._(True)._(True))).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('not', () => {
|
||||
it('not False is True', () => {
|
||||
expect(not).toDeferEvaluationOf(False);
|
||||
|
||||
+129
-39
@@ -1,41 +1,44 @@
|
||||
import { describe, expect, it } from '@jest/globals';
|
||||
import { L, toNative } from '../src/core';
|
||||
import { toNumber as $n, Num, Succ, Zero, fromNumber as _n, odd, succ, sum } from '../src/num';
|
||||
import { toArray as $, toNumberArray as $na, Cons, List, Nil, fromArray as _, fromNumberArray as _na, filter, foldl, foldlz, foldr, foldrz, head, map, tail } from '../src/list';
|
||||
import { L, _, toNative } from '../src/core';
|
||||
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, eq, filter, foldl, foldlz, foldr, foldrz, head, map, tail } from '../src/list';
|
||||
|
||||
|
||||
describe('List', () => {
|
||||
const iterate: (n: Num) => List<Num> = n => new L(() => Cons._(n)._(iterate(Succ._(n))).value);
|
||||
const infinite: List<Num> = iterate(Zero);
|
||||
|
||||
describe('toArray', () => {
|
||||
it('converts []', () => {
|
||||
expect($(Nil)).toEqual([]);
|
||||
expect($a(Nil)).toEqual([]);
|
||||
});
|
||||
|
||||
it('converts [0]', () => {
|
||||
expect($(Cons._(_n(0))._(Nil)).map($n)).toEqual([0]);
|
||||
expect($a(Cons._(_n(0))._(Nil)).map($n)).toEqual([0]);
|
||||
});
|
||||
|
||||
it('converts [0, 1]', () => {
|
||||
expect($(Cons._(_n(0))._(Cons._(_n(1))._(Nil))).map($n)).toEqual([0, 1]);
|
||||
expect($a(Cons._(_n(0))._(Cons._(_n(1))._(Nil))).map($n)).toEqual([0, 1]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('fromArray', () => {
|
||||
it('converts []', () => {
|
||||
expect($(_([]))).toEqual([]);
|
||||
expect($a(_a([]))).toEqual([]);
|
||||
});
|
||||
|
||||
it('converts [0]', () => {
|
||||
expect($(_([0].map(_n))).map($n)).toEqual([0]);
|
||||
expect($a(_a([0].map(_n))).map($n)).toEqual([0]);
|
||||
});
|
||||
|
||||
it('converts 2', () => {
|
||||
expect($(_([0, 1].map(_n))).map($n)).toEqual([0, 1]);
|
||||
expect($a(_a([0, 1].map(_n))).map($n)).toEqual([0, 1]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('head', () => {
|
||||
it('returns nothing from empty list', () => {
|
||||
it('returns nothing from Nil', () => {
|
||||
expect(() => head._(Nil)).not.toThrow();
|
||||
expect(() => toNative(head._(Nil))).toThrow();
|
||||
});
|
||||
@@ -51,12 +54,12 @@ describe('List', () => {
|
||||
});
|
||||
|
||||
it('handles infinite lists', () => {
|
||||
expect($n(head._(iterate(Zero)))).toBe(0);
|
||||
expect($n(head._(infinite))).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('tail', () => {
|
||||
it('drops nothing from empty list', () => {
|
||||
it('drops nothing from Nil', () => {
|
||||
expect(() => tail._(Nil)).not.toThrow();
|
||||
expect(() => $na(tail._(Nil))).toThrow();
|
||||
});
|
||||
@@ -72,12 +75,12 @@ describe('List', () => {
|
||||
});
|
||||
|
||||
it('handles infinite lists', () => {
|
||||
expect($n(head._(tail._(iterate(Zero))))).toBe(1);
|
||||
expect($n(head._(tail._(infinite)))).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('foldl', () => {
|
||||
it('folds empty list', () => {
|
||||
it('folds Nil', () => {
|
||||
expect(foldl._(sum)).toDeferEvaluationOf(Zero, _na([]));
|
||||
expect($n(foldl._(sum)._(Zero)._(_na([])))).toBe(0);
|
||||
});
|
||||
@@ -94,7 +97,7 @@ describe('List', () => {
|
||||
});
|
||||
|
||||
describe('foldlz', () => {
|
||||
it('does not fold empty list', () => {
|
||||
it('does not fold Nil', () => {
|
||||
expect(() => foldlz._(sum)._(Nil)).not.toThrow();
|
||||
expect(() => $n(foldlz._(sum)._(Nil))).toThrow();
|
||||
});
|
||||
@@ -111,7 +114,7 @@ describe('List', () => {
|
||||
});
|
||||
|
||||
describe('foldr', () => {
|
||||
it('folds empty list', () => {
|
||||
it('folds Nil', () => {
|
||||
expect(foldr._(sum)).toDeferEvaluationOf(Zero, _na([]));
|
||||
expect($n(foldr._(sum)._(Zero)._(_na([])))).toBe(0);
|
||||
});
|
||||
@@ -126,19 +129,18 @@ describe('List', () => {
|
||||
expect($n(foldr._(sum)._(Zero)._(_na([1, 2])))).toBe(3);
|
||||
});
|
||||
|
||||
// it('handles infinite lists', () => {
|
||||
// expect(foldr<Lazy<number>, Lazy<number>>(x => _(a =>
|
||||
// iif<Lazy<number>>
|
||||
// (x.call(x => fromBoolean(x === 0)))
|
||||
// .call(
|
||||
// (x).call(
|
||||
// (x.call(x => a.call(a => _(x + a)))))))
|
||||
// ).call((fromNumber(0)).call((iterate(-5))))).toEvaluateTo(-15);
|
||||
// });
|
||||
it('handles infinite lists', () => {
|
||||
expect($n(
|
||||
foldr
|
||||
._(_(x => _(a => iif._(eqn._(x)._(_n(5)))._(x)._(sum._(x)._(a)))))
|
||||
._(Zero)
|
||||
._(infinite)))
|
||||
.toBe(15);
|
||||
});
|
||||
});
|
||||
|
||||
describe('foldrz', () => {
|
||||
it('does not fold empty list', () => {
|
||||
it('does not fold Nil', () => {
|
||||
expect(() => foldrz._(sum)._(Nil)).not.toThrow();
|
||||
expect(() => $n(foldrz._(sum)._(Nil))).toThrow();
|
||||
});
|
||||
@@ -153,19 +155,65 @@ describe('List', () => {
|
||||
expect($n(foldrz._(sum)._(_na([1, 2])))).toBe(3);
|
||||
});
|
||||
|
||||
// it.failing('handles infinite lists', () => {
|
||||
// expect(foldrz<Lazy<number>>(x => _(a =>
|
||||
// iif<Lazy<number>>
|
||||
// (x.call(x => fromBoolean(x === 0)))
|
||||
// .call(
|
||||
// (x).call(
|
||||
// (x.call(x => a.call(a => _(x + a)))))))
|
||||
// ).call((iterate(-5)))).toEvaluateTo(-10);
|
||||
// });
|
||||
it.failing('handles infinite lists', () => {
|
||||
expect($n(
|
||||
foldrz
|
||||
._(_(x => _(a => iif._(eqn._(x)._(_n(5)))._(x)._(sum._(x)._(a)))))
|
||||
._(infinite)))
|
||||
.toBe(15);
|
||||
});
|
||||
});
|
||||
|
||||
describe('eq', () => {
|
||||
it('Nil eq Nil is True', () => {
|
||||
expect(eq).toDeferEvaluationOf(eqn, _na([]), _na([]));
|
||||
expect($b(eq._(eqn)._(_na([]))._(_na([])))).toEqual(true);
|
||||
});
|
||||
|
||||
it('Nil eq [0, 1, 2] is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(eqn, _na([]), _na([0, 1, 2]));
|
||||
expect($b(eq._(eqn)._(_na([]))._(_na([0, 1, 2])))).toEqual(false);
|
||||
});
|
||||
|
||||
it('[0, 1, 2] eq Nil is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(eqn, _na([0, 1, 2]), _na([]));
|
||||
expect($b(eq._(eqn)._(_na([0, 1, 2]))._(_na([])))).toEqual(false);
|
||||
});
|
||||
|
||||
it('[0] eq [0, 1, 2] is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(eqn, _na([0]), _na([0, 1, 2]));
|
||||
expect($b(eq._(eqn)._(_na([0]))._(_na([0, 1, 2])))).toEqual(false);
|
||||
});
|
||||
|
||||
it('[0, 1, 2] eq [0] is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(eqn, _na([0, 1, 2]), _na([0]));
|
||||
expect($b(eq._(eqn)._(_na([0, 1, 2]))._(_na([0])))).toEqual(false);
|
||||
});
|
||||
|
||||
|
||||
it('[1, 2, 0] eq [0, 1, 2] is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(eqn, _na([1, 2, 0]), _na([0, 1, 2]));
|
||||
expect($b(eq._(eqn)._(_na([1, 2, 0]))._(_na([0, 1, 2])))).toEqual(false);
|
||||
});
|
||||
|
||||
it('[0, 1, 2] eq [1, 2, 0] is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(eqn, _na([0, 1, 2]), _na([1, 2, 0]));
|
||||
expect($b(eq._(eqn)._(_na([0, 1, 2]))._(_na([1, 2, 0])))).toEqual(false);
|
||||
});
|
||||
|
||||
it('[0, 1, 2] eq [0, 1, 2] is True', () => {
|
||||
expect(eq).toDeferEvaluationOf(eqn, _na([0, 1, 2]), _na([0, 1, 2]));
|
||||
expect($b(eq._(eqn)._(_na([0, 1, 2]))._(_na([0, 1, 2])))).toEqual(true);
|
||||
});
|
||||
|
||||
it('handles infinite lists', () => {
|
||||
expect($b(eq._(eqn)._(infinite)._(_na([0, 1, 2])))).toEqual(false);
|
||||
expect($b(eq._(eqn)._(_na([0, 1, 2]))._(infinite))).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('map', () => {
|
||||
it('maps empty list', () => {
|
||||
it('maps Nil', () => {
|
||||
expect(map._(succ)).toDeferEvaluationOf(_na([]));
|
||||
expect($na(map._(succ)._(_na([])))).toEqual([]);
|
||||
});
|
||||
@@ -181,12 +229,12 @@ describe('List', () => {
|
||||
});
|
||||
|
||||
it('handles infinite lists', () => {
|
||||
expect($n(head._(map._(succ)._(iterate(Zero))))).toBe(1);
|
||||
expect($n(head._(map._(succ)._(infinite)))).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('filter', () => {
|
||||
it('filter empty list', () => {
|
||||
it('filter Nil', () => {
|
||||
expect(filter._(odd)).toDeferEvaluationOf(_na([]));
|
||||
expect($na(filter._(odd)._(_na([])))).toEqual([]);
|
||||
});
|
||||
@@ -202,7 +250,49 @@ describe('List', () => {
|
||||
});
|
||||
|
||||
it('handles infinite lists', () => {
|
||||
expect($n(head._(filter._(odd)._(iterate(Zero))))).toBe(1);
|
||||
expect($n(head._(filter._(odd)._(infinite)))).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('any', () => {
|
||||
it('any Nil is False', () => {
|
||||
expect(any._(odd)).toDeferEvaluationOf(_na([]));
|
||||
expect($b(any._(odd)._(_na([])))).toEqual(false);
|
||||
});
|
||||
|
||||
it('any for no matching item is False', () => {
|
||||
expect(any._(odd)).toDeferEvaluationOf(_na([0, 2]));
|
||||
expect($b(any._(odd)._(_na([0, 2])))).toEqual(false);
|
||||
});
|
||||
|
||||
it('any for matching item is True', () => {
|
||||
expect(any._(odd)).toDeferEvaluationOf(_na([0, 1, 2]));
|
||||
expect($b(any._(odd)._(_na([0, 1, 2])))).toEqual(true);
|
||||
});
|
||||
|
||||
it('handles infinite lists', () => {
|
||||
expect($b(any._(odd)._(infinite))).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('all', () => {
|
||||
it('all Nil is True', () => {
|
||||
expect(all._(even)).toDeferEvaluationOf(_na([]));
|
||||
expect($b(all._(even)._(_na([])))).toEqual(true);
|
||||
});
|
||||
|
||||
it('all for non-matching item is False', () => {
|
||||
expect(all._(even)).toDeferEvaluationOf(_na([0, 1, 2]));
|
||||
expect($b(all._(even)._(_na([0, 1, 2])))).toEqual(false);
|
||||
});
|
||||
|
||||
it('all for no non-matching item is True', () => {
|
||||
expect(all._(even)).toDeferEvaluationOf(_na([0, 2]));
|
||||
expect($b(all._(even)._(_na([0, 2])))).toEqual(true);
|
||||
});
|
||||
|
||||
it('handles infinite lists', () => {
|
||||
expect($b(all._(even)._(infinite))).toEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+48
-9
@@ -1,7 +1,11 @@
|
||||
import { describe, expect, it } from '@jest/globals';
|
||||
import { toNumber as $, Num, Succ, Zero, fromNumber as _, ifz, mul, pred, sub, succ, sum } from '../src/num';
|
||||
import { L } from '../src/core';
|
||||
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';
|
||||
|
||||
describe('Num', () => {
|
||||
const infinity: Num = new L(() => Succ._(infinity).value);
|
||||
|
||||
describe('toNumber', () => {
|
||||
it('converts 0', () => {
|
||||
expect($(Zero)).toBe(0);
|
||||
@@ -33,23 +37,21 @@ describe('Num', () => {
|
||||
describe('ifz', () => {
|
||||
it('returns zero branch', () => {
|
||||
expect(ifz).toDeferEvaluationOf(_(0), true, false);
|
||||
expect($(ifz._(_(0))._(_(0))._(_(1)))).toBe(0);
|
||||
expect($b(ifz._(_(0))._(_b(true))._(_b(false)))).toBe(true);
|
||||
});
|
||||
|
||||
it('returns non-zero branch', () => {
|
||||
expect(ifz).toDeferEvaluationOf(_(1), true, false);
|
||||
expect($(ifz._(_(1))._(_(0))._(_(1)))).toBe(1);
|
||||
expect($b(ifz._(_(1))._(_b(true))._(_b(false)))).toBe(false);
|
||||
});
|
||||
|
||||
it('returns non-zero branch', () => {
|
||||
expect(ifz).toDeferEvaluationOf(_(100), true, false);
|
||||
expect($(ifz._(_(10))._(_(0))._(_(1)))).toBe(1);
|
||||
expect(ifz).toDeferEvaluationOf(_(10), true, false);
|
||||
expect($b(ifz._(_(10))._(_b(true))._(_b(false)))).toBe(false);
|
||||
});
|
||||
|
||||
it('deeply lazy', () => {
|
||||
const alot: Num = _(1000000);
|
||||
expect($(ifz._(Succ._(alot))._(_(0))._(_(1)))).toBe(1);
|
||||
expect(alot.evaluated).toBe(false);
|
||||
it('handles infinity', () => {
|
||||
expect($b(ifz._(infinity)._(_b(true))._(_b(false)))).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -87,6 +89,43 @@ describe('Num', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('eq', () => {
|
||||
it('0 eq 0 is True', () => {
|
||||
expect(eq).toDeferEvaluationOf(_(0), _(0));
|
||||
expect($b(eq._(_(0))._(_(0)))).toBe(true);
|
||||
});
|
||||
|
||||
it('0 eq 1 is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(_(0), _(1));
|
||||
expect($b(eq._(_(0))._(_(1)))).toBe(false);
|
||||
});
|
||||
|
||||
it('1 eq 0 is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(_(1), _(0));
|
||||
expect($b(eq._(_(1))._(_(0)))).toBe(false);
|
||||
});
|
||||
|
||||
it('3 eq 3 is True', () => {
|
||||
expect(eq).toDeferEvaluationOf(_(3), _(4));
|
||||
expect($b(eq._(_(3))._(_(3)))).toBe(true);
|
||||
});
|
||||
|
||||
it('3 eq 7 is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(_(3), _(7));
|
||||
expect($b(eq._(_(3))._(_(7)))).toBe(false);
|
||||
});
|
||||
|
||||
it('7 eq 3 is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(_(7), _(3));
|
||||
expect($b(eq._(_(7))._(_(3)))).toBe(false);
|
||||
});
|
||||
|
||||
it('handles infinity', () => {
|
||||
expect($b(eq._(infinity)._(_(3)))).toBe(false);
|
||||
expect($b(eq._(_(7))._(infinity))).toBe(false);
|
||||
})
|
||||
});
|
||||
|
||||
describe('sum', () => {
|
||||
it('0 sum 0 is 0', () => {
|
||||
expect(sum).toDeferEvaluationOf(_(0), _(0));
|
||||
|
||||
Reference in New Issue
Block a user