More library functions
This commit is contained in:
+2
-2
@@ -1,4 +1,4 @@
|
||||
import { L, P, _, fromNative, toNative } from './core';
|
||||
import { toNative as $n, L, P, _, fromNative as _n } from './core';
|
||||
|
||||
export type Bool = L<<T extends P>(t: T) => L<(f: T) => T>>;
|
||||
|
||||
@@ -30,4 +30,4 @@ export const fromBoolean: (b: boolean) => Bool
|
||||
= b => b ? True : False;
|
||||
|
||||
export const toBoolean: (b: Bool) => boolean
|
||||
= b => toNative(b._(fromNative(true))._(fromNative(false)));
|
||||
= b => $n(b._(_n(true))._(_n(false)));
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
|
||||
import { L, _ } from './core';
|
||||
import { Bool } from './bool';
|
||||
import { toNumber as $n, Num, Zero, fromNumber as _n, eq as eqn } from './num';
|
||||
|
||||
export type Char = Num;
|
||||
|
||||
export const Null: Char
|
||||
= Zero;
|
||||
|
||||
export const eq: L<(l: Char) => L<(r: Char) => Bool>>
|
||||
= eqn;
|
||||
|
||||
export const fromChar: (c: string) => Char
|
||||
= c => _n(c.charCodeAt(0));
|
||||
|
||||
export const toChar: (c: Char) => string
|
||||
= c => String.fromCharCode($n(c));
|
||||
@@ -2,3 +2,5 @@ export * from './core';
|
||||
export * from './bool';
|
||||
export * from './num';
|
||||
export * from './list';
|
||||
export * from './char';
|
||||
export * from './pair';
|
||||
|
||||
+8
-5
@@ -1,6 +1,6 @@
|
||||
import { L, P, _, fromNative, toNative, undef } from './core';
|
||||
import { Num, fromNumber, toNumber } from './num';
|
||||
import { toNative as $n, L, P, _, fromNative as _n, undef } from './core';
|
||||
import { Bool, False, True, and, iif, or } from './bool';
|
||||
import { toNumber as $nn, Num, fromNumber as _nn } from './num';
|
||||
|
||||
export type List<T extends P> = L<<R extends P>(z: R) => L<(f: L<(x: T) => L<(xs: List<T>) => R>>) => R>>;
|
||||
|
||||
@@ -13,6 +13,9 @@ export const Cons: L<<T extends P>(x: T) => L<(xs: List<T>) => List<T>>>
|
||||
export const cons: L<<T extends P>(x: T) => L<(xs: List<T>) => List<T>>>
|
||||
= Cons;
|
||||
|
||||
export const concat: L<<T extends P>(l: List<T>) => L<(r: List<T>) => List<T>>>
|
||||
= _(l => _(r => l._(r)._(_(x => _(xs => cons._(x)._(concat._(xs)._(r)))))));
|
||||
|
||||
export const head: L<<T extends P>(xs: List<T>) => T>
|
||||
= _(xs => xs._(undef)._(_(x => _(_xs => x))));
|
||||
|
||||
@@ -74,10 +77,10 @@ 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));
|
||||
|
||||
export const fromNumberArray: (xs: number[]) => List<Num>
|
||||
= xs => xs.length === 0 ? Nil : Cons._(fromNumber(xs[0]))._(new L(() => fromNumberArray(xs.slice(1)).value));
|
||||
= xs => xs.length === 0 ? Nil : Cons._(_nn(xs[0]))._(new L(() => fromNumberArray(xs.slice(1)).value));
|
||||
|
||||
export const toArray: <T extends P>(xs: List<T>) => P[]
|
||||
= xs => toNative(xs._(fromNative([]))._(_(x => _(xs => fromNative([x, ...toArray(xs)])))));
|
||||
= xs => $n(xs._(_n([]))._(_(x => _(xs => _n([x, ...toArray(xs)])))));
|
||||
|
||||
export const toNumberArray: (xs: List<Num>) => number[]
|
||||
= xs => toNative(xs._(fromNative([]))._(_(x => _(xs => fromNative([toNumber(x), ...toNumberArray(xs)])))));
|
||||
= xs => $n(xs._(_n([]))._(_(x => _(xs => _n([$nn(x), ...toNumberArray(xs)])))));
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
import { toNative as $n, L, P, _, fromNative as _n, id } from './core';
|
||||
import { Bool, False, True } from './bool';
|
||||
import { L, P, _, fromNative, id, toNative } from './core';
|
||||
|
||||
export type Num = L<<T extends P>(z: T) => L<(n: L<(p: Num) => T>) => T>>;
|
||||
|
||||
@@ -42,4 +42,4 @@ export const fromNumber: (n: number) => Num
|
||||
= n => !n ? Zero : Succ._(new L(() => fromNumber(n - 1).value));
|
||||
|
||||
export const toNumber: (n: Num) => number
|
||||
= n => toNative(n._(fromNative(0))._(_(p => fromNative(1 + toNumber(p)))));
|
||||
= n => $n(n._(_n(0))._(_(p => _n(1 + toNumber(p)))));
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
import { L, P, _ } from './core';
|
||||
|
||||
export type Pair<F extends P, S extends P> = L<<R extends P>(f: L<(f: F) => L<(s: S) => R>>) => R>;
|
||||
|
||||
export const Pair: L<<F extends P, S extends P>(f: F) => L<(s: S) => Pair<F, S>>>
|
||||
=
|
||||
_(<F extends P, S extends P>(f: F) =>
|
||||
_((s: S) =>
|
||||
_(<R extends P>(p: L<(f: F) => L<(s: S) => R>>) => p._(f)._(s))));
|
||||
|
||||
export const fst: L<<F extends P, S extends P>(p: Pair<F, S>) => F>
|
||||
= _(p => p._(_(f => _(_s => f))));
|
||||
|
||||
export const snd: L<<F extends P, S extends P>(p: Pair<F, S>) => S>
|
||||
= _(p => p._(_(_f => _(s => s))));
|
||||
|
||||
export const first: L<<F extends P, FR extends P, S extends P>(t: L<(f: F) => FR>) => L<(p: Pair<F, S>) => Pair<FR, S>>>
|
||||
=
|
||||
_(<F extends P, FR extends P>(t: L<(f: F) => FR>) =>
|
||||
_(<S extends P>(p: Pair<F, S>) => p._(_(f => _(s => Pair._(t._(f))._(s))))));
|
||||
|
||||
export const second: L<<F extends P, S extends P, SR extends P>(t: L<(s: S) => SR>) => L<(p: Pair<F, S>) => Pair<F, SR>>>
|
||||
=
|
||||
_(<S extends P, SR extends P>(t: L<(s: S) => SR>) =>
|
||||
_(<F extends P>(p: Pair<F, S>) => p._(_(f => _(s => Pair._(f)._(t._(s)))))));
|
||||
|
||||
export const both: L<<F extends P, FR extends P, S extends P, SR extends P>(tf: L<(f: F) => FR>) => L<(ts: L<(s: S) => SR>) =>L<(p: Pair<F, S>) => Pair<FR, SR>>>>
|
||||
=
|
||||
_(<F extends P, FR extends P>(tf: L<(f: F) => FR>) =>
|
||||
_(<S extends P, SR extends P>(ts: L<(s: S) => SR>) =>
|
||||
_((p: Pair<F, S>) => p._(_(f => _(s => Pair._(tf._(f))._(ts._(s))))))));
|
||||
@@ -0,0 +1,28 @@
|
||||
import { toNative as $n, L, _, fromNative as _n } from './core';
|
||||
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';
|
||||
|
||||
export type String = List<Char>;
|
||||
|
||||
export const Empty: String
|
||||
= Nil;
|
||||
|
||||
export const Cons: L<(c: Char) => L<(s: String) => String>>
|
||||
= ConsL;
|
||||
|
||||
export const cons: L<(c: Char) => L<(s: String) => String>>
|
||||
= Cons;
|
||||
|
||||
export const concat: L<(l: String) => L<(r: String) => String>>
|
||||
= concatl;
|
||||
|
||||
export const eq: L<(l: String) => L<(r: String) => Bool>>
|
||||
= eql._(eqc);
|
||||
|
||||
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))))));
|
||||
@@ -0,0 +1,64 @@
|
||||
import { describe, expect, it } from '@jest/globals';
|
||||
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';
|
||||
|
||||
describe('Char', () => {
|
||||
describe('toChar', () => {
|
||||
it('converts "0"', () => {
|
||||
expect($(_n(48))).toBe('0');
|
||||
});
|
||||
|
||||
it('converts "a"', () => {
|
||||
expect($(_n(97))).toBe('a');
|
||||
});
|
||||
|
||||
it('converts "Z"', () => {
|
||||
expect($(_n(90))).toBe('Z');
|
||||
});
|
||||
|
||||
it('converts "-"', () => {
|
||||
expect($(_n(45))).toBe('-');
|
||||
});
|
||||
});
|
||||
|
||||
describe('fromChar', () => {
|
||||
it('converts "0"', () => {
|
||||
expect($(_('0'))).toBe('0');
|
||||
});
|
||||
|
||||
it('converts "a"', () => {
|
||||
expect($(_('a'))).toBe('a');
|
||||
});
|
||||
|
||||
it('converts "Z"', () => {
|
||||
expect($(_('Z'))).toBe('Z');
|
||||
});
|
||||
|
||||
it('converts "-"', () => {
|
||||
expect($(_('-'))).toBe('-');
|
||||
});
|
||||
});
|
||||
|
||||
describe('eq', () => {
|
||||
it('"0" eq "0" is True', () => {
|
||||
expect(eq).toDeferEvaluationOf(_('0'), _('0'));
|
||||
expect($b(eq._(_('0'))._(_('0')))).toBe(true);
|
||||
});
|
||||
|
||||
it('"0" eq "a" is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(_('0'), _('a'));
|
||||
expect($b(eq._(_('0'))._(_('a')))).toBe(false);
|
||||
});
|
||||
|
||||
it('"a" eq "a" is True', () => {
|
||||
expect(eq).toDeferEvaluationOf(_('a'), _('a'));
|
||||
expect($b(eq._(_('a'))._(_('a')))).toBe(true);
|
||||
});
|
||||
|
||||
it('"a" eq "z" is True', () => {
|
||||
expect(eq).toDeferEvaluationOf(_('a'), _('z'));
|
||||
expect($b(eq._(_('a'))._(_('z')))).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
+44
-3
@@ -1,9 +1,8 @@
|
||||
import { describe, expect, it } from '@jest/globals';
|
||||
import { L, _, toNative } from '../src/core';
|
||||
import { L, _, toNative, undef } 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';
|
||||
|
||||
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';
|
||||
|
||||
describe('List', () => {
|
||||
const iterate: (n: Num) => List<Num> = n => new L(() => Cons._(n)._(iterate(Succ._(n))).value);
|
||||
@@ -37,6 +36,48 @@ describe('List', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('cons', () => {
|
||||
it('0 cons Nil is [0]', () => {
|
||||
expect(cons).toDeferEvaluationOf(_n(0), Nil);
|
||||
expect($na(cons._(_n(0))._(Nil))).toEqual([0]);
|
||||
});
|
||||
|
||||
it('0 cons [1] is [0, 1]', () => {
|
||||
expect(cons).toDeferEvaluationOf(_n(0), _na([1]));
|
||||
expect($na(cons._(_n(0))._(_na([1])))).toEqual([0, 1]);
|
||||
});
|
||||
|
||||
it('0 cons [1, 2] is [0, 1, 2]', () => {
|
||||
expect(cons).toDeferEvaluationOf(_n(0), _na([1, 2]));
|
||||
expect($na(cons._(_n(0))._(_na([1, 2])))).toEqual([0, 1, 2]);
|
||||
});
|
||||
|
||||
it('handles infinite lists', () => {
|
||||
expect($n(cons._(_n(0))._(infinite)._(undef)._(_(x => _(_xs => x))))).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('concat', () => {
|
||||
it('Nil concat Nil is Nil', () => {
|
||||
expect(concat).toDeferEvaluationOf(Nil, Nil);
|
||||
expect($na(concat._(Nil)._(Nil))).toEqual([]);
|
||||
});
|
||||
|
||||
it('[0] concat [1] is [0, 1]', () => {
|
||||
expect(concat).toDeferEvaluationOf(_na([0]), _na([1]));
|
||||
expect($na(concat._(_na([0]))._(_na([1])))).toEqual([0, 1]);
|
||||
});
|
||||
|
||||
it('[0, 1] concat [2, 3] is [0, 1, 2, 3]', () => {
|
||||
expect(concat).toDeferEvaluationOf(_na([0, 1]), _na([2, 3]));
|
||||
expect($na(concat._(_na([0, 1]))._(_na([2, 3])))).toEqual([0, 1, 2, 3]);
|
||||
});
|
||||
|
||||
it('handles infinite lists', () => {
|
||||
expect($n(concat._(infinite)._(infinite)._(undef)._(_(x => _(_xs => x))))).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('head', () => {
|
||||
it('returns nothing from Nil', () => {
|
||||
expect(() => head._(Nil)).not.toThrow();
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
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';
|
||||
|
||||
describe('Pair', () => {
|
||||
describe('fst', () => {
|
||||
it('returns first', () => {
|
||||
expect($b(fst._(Pair._(_b(false))._(_n(0))))).toBe(false);
|
||||
});
|
||||
|
||||
it('ignores second', () => {
|
||||
expect($b(fst._(Pair._(_b(false))._(undef)))).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('snd', () => {
|
||||
it('returns second', () => {
|
||||
expect($n(snd._(Pair._(_b(false))._(_n(0))))).toBe(0);
|
||||
});
|
||||
|
||||
it('ignores first', () => {
|
||||
expect($n(snd._(Pair._(undef)._(_n(0))))).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('first', () => {
|
||||
it('updates first', () => {
|
||||
expect($b(fst._(first._(not)._(Pair._(_b(false))._(_n(0)))))).toBe(true);
|
||||
});
|
||||
|
||||
it('ignores second', () => {
|
||||
expect($b(fst._(first._(not)._(Pair._(_b(false))._(undef))))).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('second', () => {
|
||||
it('updates second', () => {
|
||||
expect($n(snd._(second._(succ)._(Pair._(_b(false))._(_n(0)))))).toBe(1);
|
||||
});
|
||||
|
||||
it('ignores first', () => {
|
||||
expect($n(snd._(second._(succ)._(Pair._(undef)._(_n(0)))))).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('both', () => {
|
||||
it('updates both', () => {
|
||||
expect($b(fst._(both._(not)._(succ)._(Pair._(_b(false))._(_n(0)))))).toBe(true);
|
||||
expect($n(snd._(both._(not)._(succ)._(Pair._(_b(false))._(_n(0)))))).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,106 @@
|
||||
import { describe, expect, it } from '@jest/globals';
|
||||
import { L, _, undef } from '../src/core';
|
||||
import { toBoolean as $b } from '../src/bool';
|
||||
import { toChar as $c, fromChar as _c, eq as eqc } from '../src/char';
|
||||
import { toString as $s, Cons, Empty, String, fromString as _s, concat, eq } from '../src/string';
|
||||
|
||||
describe('String', () => {
|
||||
const infinite: String = new L(() => Cons._(_c('a'))._(infinite).value);;
|
||||
|
||||
describe('toString', () => {
|
||||
it('converts ""', () => {
|
||||
expect($s(Empty)).toBe('');
|
||||
});
|
||||
|
||||
it('converts "a"', () => {
|
||||
expect($s(Cons._(_c('a'))._(Empty))).toBe('a');
|
||||
});
|
||||
|
||||
it('converts "abc"', () => {
|
||||
expect($s(Cons._(_c('a'))._(Cons._(_c('b'))._(Cons._(_c('c'))._(Empty))))).toBe('abc');
|
||||
});
|
||||
});
|
||||
|
||||
describe('fromString', () => {
|
||||
it('converts ""', () => {
|
||||
expect($s(_s(''))).toBe('');
|
||||
});
|
||||
|
||||
it('converts "a"', () => {
|
||||
expect($s(_s('a'))).toBe('a');
|
||||
});
|
||||
|
||||
it('converts "2"', () => {
|
||||
expect($s(_s('abc'))).toBe('abc');
|
||||
});
|
||||
});
|
||||
|
||||
describe('concat', () => {
|
||||
it('"" concat "" is ""', () => {
|
||||
expect(concat).toDeferEvaluationOf(Empty, Empty);
|
||||
expect($s(concat._(Empty)._(Empty))).toBe('');
|
||||
});
|
||||
|
||||
it('"a" concat "b" is "ab"', () => {
|
||||
expect(concat).toDeferEvaluationOf(_s('a'), _s('b'));
|
||||
expect($s(concat._(_s('a'))._(_s('b')))).toBe('ab');
|
||||
});
|
||||
|
||||
it('"abc" concat "def" is "abcdef"', () => {
|
||||
expect(concat).toDeferEvaluationOf(_s('abc'), _s('def'));
|
||||
expect($s(concat._(_s('abc'))._(_s('def')))).toBe('abcdef');
|
||||
});
|
||||
|
||||
it('handles infinite lists', () => {
|
||||
expect($c(concat._(infinite)._(infinite)._(undef)._(_(x => _(_xs => x))))).toBe('a');
|
||||
});
|
||||
});
|
||||
|
||||
describe('eq', () => {
|
||||
it('"" eq "" is True', () => {
|
||||
expect(eq).toDeferEvaluationOf(eqc, _s(''), _s(''));
|
||||
expect($b(eq._(_s(''))._(_s('')))).toBe(true);
|
||||
});
|
||||
|
||||
it('"" eq "abc" is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(eqc, _s(''), _s("abc"));
|
||||
expect($b(eq._(_s(''))._(_s("abc")))).toBe(false);
|
||||
});
|
||||
|
||||
it('"abc" eq "" is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(eqc, _s("abc"), _s(''));
|
||||
expect($b(eq._(_s("abc"))._(_s('')))).toBe(false);
|
||||
});
|
||||
|
||||
it('"a" eq "abc" is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(eqc, _s('a'), _s("abc"));
|
||||
expect($b(eq._(_s('a'))._(_s("abc")))).toBe(false);
|
||||
});
|
||||
|
||||
it('"abc" eq "a" is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(eqc, _s("abc"), _s('a'));
|
||||
expect($b(eq._(_s("abc"))._(_s('a')))).toBe(false);
|
||||
});
|
||||
|
||||
|
||||
it('"bca" eq "abc" is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(eqc, _s("bca"), _s("abc"));
|
||||
expect($b(eq._(_s("bca"))._(_s("abc")))).toBe(false);
|
||||
});
|
||||
|
||||
it('"abc" eq "bca" is False', () => {
|
||||
expect(eq).toDeferEvaluationOf(eqc, _s("abc"), _s("bca"));
|
||||
expect($b(eq._(_s("abc"))._(_s("bca")))).toBe(false);
|
||||
});
|
||||
|
||||
it('"abc" eq "abc" is True', () => {
|
||||
expect(eq).toDeferEvaluationOf(eqc, _s("abc"), _s("abc"));
|
||||
expect($b(eq._(_s("abc"))._(_s("abc")))).toBe(true);
|
||||
});
|
||||
|
||||
it('handles infinite lists', () => {
|
||||
expect($b(eq._(infinite)._(_s("abc")))).toBe(false);
|
||||
expect($b(eq._(_s("abc"))._(infinite))).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user