Native syntax

master
Freywar Ulvnaudgari 2 years ago
parent c421f4123d
commit b8390cda26
  1. 3
      eslint.config.mjs
  2. 1
      profile.json
  3. 36
      src/bf.ts
  4. 2
      src/bool.show.ts
  5. 26
      src/bool.ts
  6. 2
      src/byte.show.ts
  7. 44
      src/byte.ts
  8. 2
      src/char.show.ts
  9. 415
      src/core.ts
  10. 10
      src/index.ts
  11. 2
      src/list.show.ts
  12. 62
      src/list.ts
  13. 4
      src/log.ts
  14. 2
      src/num.show.ts
  15. 38
      src/num.ts
  16. 2
      src/ord.show.ts
  17. 16
      src/ord.ts
  18. 2
      src/pair.show.ts
  19. 26
      src/pair.ts
  20. 2
      src/string.show.ts
  21. 18
      src/string.ts
  22. 14
      test/list.spec.ts
  23. 4
      test/string.spec.ts

@ -39,7 +39,8 @@ export default [
'@stylistic/indent': 'error',
'@stylistic/arrow-parens': ['error', 'as-needed', { requireForBlockBody: false }],
'@stylistic/max-statements-per-line': 'off',
'@stylistic/member-delimiter-style': 'error',
'@stylistic/member-delimiter-style': 'off',
'@stylistic/ts/member-delimiter-style': 'error',
'@typescript-eslint/no-unused-vars': [
'error',
{

@ -0,0 +1 @@
{"pid":0,"tid":0,"displayTimeUnit":"ns","traceEvents":[{"name":"Succ (Succ Zero) `0` (\\ p . `deferred`)","cat":"call","ph":"X","ts":156657.004,"dur":4630.765999999994,"args":{"cat":"call","id":81,"bindings":{},"result":"`2`"}},{"name":"Succ (Succ Zero) `0`","cat":"call","ph":"X","ts":156937.875,"dur":1203.091999999998,"args":{"cat":"call","id":79,"bindings":{},"result":"\\ n . n p"}},{"name":"Succ (Succ Zero)","cat":"call","ph":"X","ts":156964.502,"dur":999.0829999999846,"args":{"cat":"call","id":77,"bindings":{},"result":"\\ _ n . n p"}},{"name":"Succ","cat":"deref","ph":"X","ts":157046.28,"dur":165.08000000001744,"args":{"cat":"deref","id":44,"bindings":{},"result":"\\ p _ n . n p"}},{"name":"p = Succ Zero","cat":"binding","ph":"X","ts":157596.17700000003,"dur":191.69899999999984,"args":{"cat":"binding","result":"\\ _ n . n p"}},{"name":"_ = `0`","cat":"binding","ph":"X","ts":158066.72,"dur":31.12400000000548,"args":{"cat":"binding","result":"\\ n . n p"}},{"name":"n = \\ p . `deferred`","cat":"binding","ph":"X","ts":158272.001,"dur":33.950000000004366,"args":{"cat":"binding","result":"n p"}},{"name":"n p","cat":"call","ph":"X","ts":158348.008,"dur":2912.5020000000177,"args":{"cat":"call","id":95,"bindings":{},"result":"`2`"}},{"name":"n","cat":"deref","ph":"X","ts":158369.886,"dur":17.241999999981772,"args":{"cat":"deref","id":94,"bindings":{},"result":"\\ p . `deferred`"}},{"name":"p = p","cat":"binding","ph":"X","ts":158425.804,"dur":83.39300000000094,"args":{"cat":"binding","result":"`deferred`"}},{"name":"`deferred`","cat":"deferred","ph":"X","ts":158620.56999999998,"dur":2614.6190000000047,"args":{"cat":"deferred","id":96,"bindings":{},"result":"`2`"}},{"name":"p `0` (\\ p . `deferred`)","cat":"call","ph":"X","ts":158825.965,"dur":2367.5389999999934,"args":{"cat":"call","id":100,"bindings":{},"result":"`1`"}},{"name":"p `0`","cat":"call","ph":"X","ts":158855.655,"dur":527.1789999999896,"args":{"cat":"call","id":98,"bindings":{},"result":"\\ n . n p"}},{"name":"p","cat":"deref","ph":"X","ts":158870.886,"dur":410.04099999997834,"args":{"cat":"deref","id":90,"bindings":{},"result":"\\ _ n . n p"}},{"name":"Succ Zero","cat":"call","ph":"X","ts":158883.601,"dur":256.76500000000146,"args":{"cat":"call","id":76,"bindings":{},"result":"\\ _ n . n p"}},{"name":"Succ [cached]","cat":"deref","ph":"X","ts":158898.10199999998,"dur":11.87500000000341,"args":{"cat":"deref","id":44,"bindings":{},"result":"\\ p _ n . n p"}},{"name":"p = Zero","cat":"binding","ph":"X","ts":159030.766,"dur":50.10999999998944,"args":{"cat":"binding","result":"\\ _ n . n p"}},{"name":"_ = `0`","cat":"binding","ph":"X","ts":159331.049,"dur":16.565999999983205,"args":{"cat":"binding","result":"\\ n . n p"}},{"name":"n = \\ p . `deferred`","cat":"binding","ph":"X","ts":159416.566,"dur":34.87000000001217,"args":{"cat":"binding","result":"n p"}},{"name":"n p","cat":"call","ph":"X","ts":159496.194,"dur":1663.6980000000108,"args":{"cat":"call","id":108,"bindings":{},"result":"`1`"}},{"name":"n","cat":"deref","ph":"X","ts":159508.905,"dur":18.496999999996433,"args":{"cat":"deref","id":107,"bindings":{},"result":"\\ p . `deferred`"}},{"name":"p = p","cat":"binding","ph":"X","ts":159559.526,"dur":17.22300000000132,"args":{"cat":"binding","result":"`deferred`"}},{"name":"`deferred`","cat":"deferred","ph":"X","ts":159623.762,"dur":1484.644000000003,"args":{"cat":"deferred","id":109,"bindings":{},"result":"`1`"}},{"name":"p `0` (\\ p . `deferred`)","cat":"call","ph":"X","ts":159688.99899999998,"dur":1330.6300000000135,"args":{"cat":"call","id":113,"bindings":{},"result":"`0`"}},{"name":"p `0`","cat":"call","ph":"X","ts":159707.248,"dur":1215.9960000000183,"args":{"cat":"call","id":111,"bindings":{},"result":"\\ _ . z"}},{"name":"p","cat":"deref","ph":"X","ts":159722.568,"dur":165.2430000000038,"args":{"cat":"deref","id":103,"bindings":{},"result":"\\ z _ . z"}},{"name":"Zero","cat":"deref","ph":"X","ts":159733.117,"dur":96.05600000000436,"args":{"cat":"deref","id":42,"bindings":{},"result":"\\ z _ . z"}},{"name":"z = `0`","cat":"binding","ph":"X","ts":159931.713,"dur":944.1280000000063,"args":{"cat":"binding","result":"\\ _ . z"}},{"name":"_ = \\ p . `deferred`","cat":"binding","ph":"X","ts":160955.41199999998,"dur":12.740000000007967,"args":{"cat":"binding","result":"z"}},{"name":"z","cat":"deref","ph":"X","ts":160988.294,"dur":12.250999999992018,"args":{"cat":"deref","id":119,"bindings":{},"result":"`0`"}}]}

@ -1,50 +1,50 @@
import { _, _l, cnst, g, id, n, pipe } from './core';
import { iif } from './bool';
import { Zero, ge, ifz, pred, succ } from './num';
import { x00 } from './byte';
import { fromChar as _c, dec as cdec, inc as cinc, eq, ifn } from './char';
import { Pair, first, fst, second, snd, uncurry } from './pair';
import { cnst, g, id, n, pipe } from './core';
import { cons, head, repeat, set, singleton, tail, update } from './list';
import { Zero, ge, ifz, pred, succ } from './num';
import { Pair, first, fst, second, snd, uncurry } from './pair';
import { Empty, get, len, snoc } from './string';
n('bf');
const done = g('done', uncurry._(_l(p => cnst._(uncurry._(_l(is => _l(cs => ge._(head._(is))._(len._(cs)))))._(p)))));
const done = g('done', uncurry._(p => cnst._(uncurry._(is => cs => ge._(head._(is))._(len._(cs)))._(p))));
const command = g('command', _l(c => uncurry._(_l(p => cnst._(eq._(c)._(uncurry._(pipe._(get)._(head))._(p)))))));
const command = g('command', c => uncurry._(p => cnst._(eq._(c)._(uncurry._(pipe._(get)._(head))._(p)))));
const advance = g('advance', first._(first._(update._(succ)._(Zero))));
const save = g('save', first._(first._(_l(is => cons._(head._(is))._(is)))));
const save = g('save', first._(first._(is => cons._(head._(is))._(is))));
const restore = g('restore', first._(first._(tail)));
const reset = g('reset', first._(first._(_l(is => cons._(head._(is))._(tail._(tail._(is)))))));
const reset = g('reset', first._(first._(is => cons._(head._(is))._(tail._(tail._(is))))));
const inc = g('inc', second._(first._(_l(t => second._(update._(cinc)._(fst._(t)))._(t)))));
const inc = g('inc', second._(first._(t => second._(update._(cinc)._(fst._(t)))._(t))));
const dec = g('dec', second._(first._(_l(t => second._(update._(cdec)._(fst._(t)))._(t)))));
const dec = g('dec', second._(first._(t => second._(update._(cdec)._(fst._(t)))._(t))));
const read = g('read', pipe._(pipe._(uncurry._(get))._(fst))._(snd));
const input = g('input', second._(uncurry._(_l(t => _l(io => Pair._(second._(set._(head._(fst._(io)))._(fst._(t)))._(t))._(first._(tail)._(io)))))));
const input = g('input', second._(uncurry._(t => io => Pair._(second._(set._(head._(fst._(io)))._(fst._(t)))._(t))._(first._(tail)._(io)))));
const output = g('output', second._(uncurry._(_l(t => pipe._(Pair._(t))._(second._(_l(os => snoc._(os)._(uncurry._(get)._(t)))))))));
const output = g('output', second._(uncurry._(t => pipe._(Pair._(t))._(second._(os => snoc._(os)._(uncurry._(get)._(t)))))));
const next = g('next', second._(first._(first._(succ))));
const prev = g('prev', second._(first._(first._(pred))));
const jump = g('jump', _l(d => _l(s =>
const jump = g('jump', d => s =>
iif._(command._(_c('['))._(s))._(jump._(succ._(d)))
._(iif._(command._(_c(']'))._(s))._(ifz._(pred._(d))._(cnst._(s))._(jump._(pred._(d))))
._(jump._(d)))._(advance._(s)))));
._(jump._(d)))._(advance._(s)));
const whlnz = g('whlnz', _l(s => ifn._(read._(s))._(jump._(Zero))._(save)._(s)));
const whlnz = g('whlnz', s => ifn._(read._(s))._(jump._(Zero))._(save)._(s));
const endwhl = g('endwhl', _l(s => ifn._(read._(s))._(reset)._(pipe._(save)._(restore))._(s)));
const endwhl = g('endwhl', s => ifn._(read._(s))._(reset)._(pipe._(save)._(restore))._(s));
const exec = g('exec', _l(s => iif._(done._(s))._(s)._(exec._(advance
const exec = g('exec', s => iif._(done._(s))._(s)._(exec._(advance
._(iif._(command._(_c('>'))._(s))._(next)
._(iif._(command._(_c('<'))._(s))._(prev)
._(iif._(command._(_c('+'))._(s))._(inc)
@ -53,6 +53,6 @@ const exec = g('exec', _l(s => iif._(done._(s))._(s)._(exec._(advance
._(iif._(command._(_c(','))._(s))._(input)
._(iif._(command._(_c('['))._(s))._(whlnz)
._(iif._(command._(_c(']'))._(s))._(endwhl)
._(id))))))))._(s))))));
._(id))))))))._(s)))));
export const run = g('run', _l(p => _l(i => snd._(snd._(snd._(exec._(Pair._(Pair._(singleton._(Zero))._(p))._(Pair._(Pair._(Zero)._(repeat._(x00)))._(Pair._(i)._(Empty))))))))));
export const run = g('run', p => i => snd._(snd._(snd._(exec._(Pair._(Pair._(singleton._(Zero))._(p))._(Pair._(Pair._(Zero)._(repeat._(x00)))._(Pair._(i)._(Empty))))))));

@ -4,4 +4,4 @@ import { fromString as _s } from './string';
n('bool.show');
export const show = g('show', _l(b => iif._(b)._(_s('True'))._(_s('False'))));
export const show = g('show', b => iif(b)(_s('True'))(_s('False')));

@ -3,32 +3,32 @@ import { EQ, GT, LT } from './ord';
n('bool');
export const True = g('True', _l(t => _l(_ => t)));
export const True = g('True', t => _ => t);
export const False = g('False', _l(_ => _l(f => f)));
export const False = g('False', _ => f => f);
export const iif = g('iif', id);
export const not = g('not', _l(b => b._(False)._(True)));
export const not = g('not', b => b(False)(True));
export const cmp = g('cmp', _l(l => _l(r => l._(r._(EQ)._(GT))._(r._(LT)._(EQ)))));
export const cmp = g('cmp', l => r => l(r(EQ)(GT))(r(LT)(EQ)));
export const lt = g('lt', _l(l => l._(False)));
export const lt = g('lt', l => l(False));
export const le = g('le', _l(l => not._(l)._(True)));
export const le = g('le', l => not(l)(True));
export const eq = g('eq', _l(l => _l(r => l._(r)._(not._(r)))));
export const eq = g('eq', l => r => l(r)(not(r)));
export const ge = g('ge', _l(l => pipe._(not)._(lt._(l))));
export const ge = g('ge', l => pipe(not)(lt(l)));
export const gt = g('gt', _l(l => pipe._(not)._(le._(l))));
export const gt = g('gt', l => pipe(not)(le(l)));
export const and = g('and', _l(l => not._(l)._(False)));
export const and = g('and', l => not(l)(False));
export const or = g('or', _l(l => l._(True)));
export const or = g('or', l => l(True));
export const xor = g('xor', _l(l => _l(r => l._(not._(r))._(r))));
export const xor = g('xor', l => r => l(not(r))(r));
export const fromBoolean: (b: boolean) => Term = b => b ? True : False;
export const toBoolean: (b: Term) => boolean = b => $(b._(_(true))._(_(false)).reduce());
export const toBoolean: (b: Term) => boolean = b => $(b(_(true))(_(false)).reduce());

@ -4,4 +4,4 @@ import { show as nshow } from './num.show';
n('byte.show');
export const show = g('show', _l(n => nshow._(snd._(n))));
export const show = g('show', n => nshow(snd(n)));

@ -1,50 +1,50 @@
import { Term, _, _l, cnst, g, n } from './core';
import { iif } from './bool';
import { toNumber as $n, Zero, fromNumber as _n, cmp as ncmp, eq as neq, even as neven, ge as nge, gt as ngt, le as nle, lt as nlt, odd as nodd, pred, succ } from './num';
import { toNumber as $n, Zero, fromNumber as _n, cmp as ncmp, eq as neq, even as neven, ge as nge, gt as ngt, le as nle, lt as nlt, odd as nodd, succ } from './num';
import { Pair, snd, uncurry } from './pair';
n('byte');
export const x00 = g('x00', Pair._(_n(255))._(Zero));
export const x00 = g('x00', Pair(_n(255))(Zero));
export const xFF = g('xFF', Pair._(Zero)._(_n(255)));
export const xFF = g('xFF', Pair(Zero)(_n(255)));
export const Inc = g('Inc', uncurry._(_l(i => _l(s => i._(x00)._(_l(pi => Pair._(pi)._(succ._(s))))))));
export const Inc = g('Inc', uncurry(i => s => i(x00)(pi => Pair(pi)(succ(s)))));
export const ifz = g('ifz', _l(n => _l(t => _l(f => snd._(n)._(t)._(cnst._(f))))));
export const ifz = g('ifz', n => t => f => snd(n)(t)(cnst(f)));
export const inc = g('inc', Inc);
export const dec = g('dec', _l(n => uncurry._(_l(i => _l(s => s._(xFF)._(_l(ps => Pair._(succ._(i))._(ps))))))._(n)));
export const dec = g('dec', n => uncurry(i => s => s(xFF)(ps => Pair(succ(i))(ps)))(n));
export const cmp = g('cmp', _l(l => _l(r => ncmp._(snd._(l))._(snd._(r)))));
export const cmp = g('cmp', l => r => ncmp(snd(l))(snd(r)));
export const lt = g('lt', _l(l => _l(r => nlt._(snd._(l))._(snd._(r)))));
export const lt = g('lt', l => r => nlt(snd(l))(snd(r)));
export const le = g('le', _l(l => _l(r => nle._(snd._(l))._(snd._(r)))));
export const le = g('le', l => r => nle(snd(l))(snd(r)));
export const eq = g('eq', _l(l => _l(r => neq._(snd._(l))._(snd._(r)))));
export const eq = g('eq', l => r => neq(snd(l))(snd(r)));
export const ge = g('ge', _l(l => _l(r => nge._(snd._(l))._(snd._(r)))));
export const ge = g('ge', l => r => nge(snd(l))(snd(r)));
export const gt = g('gt', _l(l => _l(r => ngt._(snd._(l))._(snd._(r)))));
export const gt = g('gt', l => r => ngt(snd(l))(snd(r)));
export const even = g('even', _l(l => _l(r => neven._(snd._(l))._(snd._(r)))));
export const even = g('even', l => r => neven(snd(l))(snd(r)));
export const odd = g('odd', _l(l => _l(r => nodd._(snd._(l))._(snd._(r)))));
export const odd = g('odd', l => r => nodd(snd(l))(snd(r)));
export const sum = g('sum', _l(l => _l(r => snd._(r)._(l)._(_l(_ => sum._(inc._(l))._(dec._(r)))))));
export const sum = g('sum', l => r => snd(r)(l)(_ => sum(inc(l))(dec(r))));
export const sub = g('sub', _l(l => _l(r => snd._(r)._(l)._(_l(_ => sub._(dec._(l))._(dec._(r)))))));
export const sub = g('sub', l => r => snd(r)(l)(_ => sub(dec(l))(dec(r))));
export const mul = g('mul', _l(l => _l(r => snd._(l)._(x00)._(_l(_ => sum._(r)._(mul._(dec._(l))._(r)))))));
export const mul = g('mul', l => r => snd(l)(x00)(_ => sum(r)(mul(dec(l))(r))));
export const div = g('div', _l(l => _l(r => iif._(lt._(l)._(r))._(x00)._(inc._(div._(sub._(l)._(r))._(r))))));
export const div = g('div', l => r => iif(lt(l)(r))(x00)(inc(div(sub(l)(r))(r))));
export const mod = g('mod', _l(l => _l(r => iif._(lt._(l)._(r))._(l)._(mod._(sub._(l)._(r))._(r)))));
export const mod = g('mod', l => r => iif(lt(l)(r))(l)(mod(sub(l)(r))(r)));
export const byte = g('byte', _l(n => n._(x00)._(_l(pn => inc._(byte._(pn))))));
export const byte = g('byte', n => n(x00)(pn => inc(byte(pn))));
export const fromNumber: (n: number) => Term = n => !n ? x00 : Inc._(_(() => fromNumber(n - 1)));
export const fromNumber: (n: number) => Term = n => !n ? x00 : Inc(_(() => fromNumber(n - 1)));
export const toNumber: (n: Term) => number = n => $n(snd._(n));
export const toNumber: (n: Term) => number = n => $n(snd(n));

@ -4,4 +4,4 @@ import { fromString as _s, wrap } from './string';
n('char.show');
export const show = g('show', _l(c => pipe._(wrap._(_s('\'')))._(singleton)._(c)));
export const show = g('show', c => pipe(wrap(_s('\'')))(singleton)(c));

@ -12,272 +12,209 @@ const withProfile = (term: Term, action: string, func: () => Term) => simpleWith
let index = 0;
export abstract class Term {
public id = index++;
public cache: Term | null = null;
public constructor() { }
public refs(_name: string): boolean {
return false;
}
public bound(_name: string): boolean {
return false;
}
public get bindings(): Record<string, Term> {
return {};
}
public bind(_name: string, _term: Term): Term {
return this;
}
public reduce(): Term {
return this;
}
public context(): string {
return `#${this.id}${this.cache ? '<cached>' : ''}${!Object.keys(this.bindings).length ? '' : ` [${Object.keys(this.bindings).join(', ')}]`}`;
}
public expression(): string {
return this.constructor.name;
}
public stringify(): string {
return `${this.context()} ${this.expression()}`;
}
public _(arg: Term): Term {
return new Call(this, arg);
}
public toString(): string {
return this.expression();
}
public toJSON(): string {
return `<${this.expression()}>`;
}
}
export class Undef extends Term {
constructor() { super(); }
override reduce(): Term {
interface TermBase {
type: string;
id: number;
cache: Term | null;
refs(name: string): boolean;
bound(name: string): boolean;
bindings(): Record<string, Term>;
bind(name: string, term: Term): Term;
reduce(): Term;
context(): string;
expression(): string;
stringify(): string;
_(arg: LambdaLike): Term;
(arg: LambdaLike): Term;
}
function isTerm(value: any): value is Term {
return value && value.type;
}
function makeTerm(): TermBase {
const term: Term = Object.assign(
(arg: LambdaLike) => makeCall(term, isTerm(arg) ? arg : _l(arg)),
{
type: 'T',
id: index++,
cache: null,
refs: () => false,
bound: () => false,
bindings: () => ({}),
bind: () => term,
reduce: () => term,
context: () => `${term.type}#${term.id}${term.cache ? '<cached>' : ''}${!Object.keys(term.bindings()).length ? '' : ` [${Object.keys(term.bindings()).join(', ')}]`}`,
expression: () => `\`${term.type}\``,
stringify: () => `${term.context()} ${term.expression()}`,
toString: () => term.expression(),
toJSON: () => `<${term.expression()}>`,
_: (arg: LambdaLike) => term(arg),
}) as Term;
return term;
}
interface Undef extends TermBase {
type: 'undef';
}
function makeUndef(): Undef {
const term: Undef = Object.assign(makeTerm(), {
type: 'undef' as const,
reduce: () => {
throw new Error('undef');
}
}
export class Native extends Term {
public constructor(
public value: any,
) { super(); }
public override expression(): string {
return `\`${JSON.stringify(this.value)}\``;
}
public override stringify(): string {
return this.expression();
}
}
export class Deferred extends Term {
public constructor(
protected func: (bindings: Record<string, Term>) => Term,
protected _bindings: Record<string, Term> = {},
) { super(); }
public override refs(_name: string): boolean {
return true;
},
});
return term;
}
public override bound(name: string): boolean {
return !!this._bindings[name];
interface Native extends TermBase {
type: 'N';
value: any;
}
public override get bindings(): Record<string, Term> {
return this._bindings;
function makeNative(value: any): Native {
const term: Native = Object.assign(makeTerm(), {
type: 'N' as const,
value,
expression: () => `\`${JSON.stringify(value)}\``,
stringify: () => term.expression(),
});
return term;
}
public override bind(name: string, term: Term): Term {
return this.bound(name) || !this.refs(name)
? this
: new Deferred(this.func, { ...this.bindings, [name]: term });
interface Deferred extends TermBase {
type: 'D';
}
public override reduce(): Term {
return this.cache = withLog(
`Executing ${this.stringify()}`,
function makeDeferred(func: (bindings: Record<string, Term>) => Term, bindings: Record<string, Term> = {}): Deferred {
const term: Deferred = Object.assign(makeTerm(), {
type: 'D' as const,
refs: () => true,
bound: (n: string) => !!bindings[n],
bindings: () => bindings,
bind: (n: string, t: Term) =>
term.bound(n) || !term.refs(n)
? term
: makeDeferred(func, { ...bindings, [n]: t }),
reduce: () => term.cache = withLog(
`Executing ${term.stringify()}`,
() => withProfile(
this,
term,
'deferred',
() => this.cache ?? Object.entries(this.bindings).reduce((t, b) => t.bind(...b), this.func(this.bindings)).reduce(),
() => term.cache ?? Object.entries(bindings).reduce((t, b) => t.bind(...b), func(bindings)).reduce(),
),
r => `got ${r.stringify()}`,
);
}
public override expression(): string {
return '`deferred`';
}
}
export class Ref extends Term {
public constructor(
protected namespace: string,
protected name: string,
protected binding: Term | null = null,
) { super(); }
public override refs(name: string): boolean {
return this.name === name;
}
public override bound(name: string): boolean {
return this.name === name && !!this.binding;
}
public override get bindings(): Record<string, Term> {
return this.binding ? { [this.name]: this.binding } : {};
),
});
return term;
}
public override bind(name: string, term: Term): Term {
return this.bound(name) || !this.refs(name)
? this
: new Ref(this.namespace, this.name, term);
interface Ref extends TermBase {
type: 'R';
}
public override reduce(): Term {
return this.cache = withLog(
`Substituting ${this.stringify()}`,
function makeRef(namespace: string, name: string, binding: Term | null = null): Ref {
const term: Ref = Object.assign(makeTerm(), {
type: 'R' as const,
refs: (n: string) => name === n,
bound: (n: string) => name === n && !!binding,
bindings: () => binding ? { [name]: binding } : {},
bind: (n: string, t: Term) => term.bound(n) || !term.refs(n)
? term
: makeRef(namespace, name, t),
reduce: () => term.cache = withLog(
`Substituting ${term.stringify()}`,
() => withProfile(
this,
term,
'deref',
() => this.cache ?? ((this.namespace === 'local' ? this.binding : globals[`${this.namespace}::${this.name}`]) ?? new Undef()).reduce(),
() => term.cache ?? ((namespace === 'local' ? binding : globals[`${namespace}::${name}`]) ?? makeUndef()).reduce(),
),
r => `with ${r.stringify()}`,
);
),
expression: () => name,
});
return term;
}
public override expression(): string {
return this.name;
}
interface Lambda extends TermBase {
type: 'L';
param(): string;
body(): Term;
}
export class Lambda extends Term {
public constructor(resolve: (p: Ref) => Term);
public constructor(param: string, body: Term);
public constructor(
resolveOrParam: ((p: Ref) => Term) | string,
function makeLambda(resolve: (p: Term) => LambdaLike): Lambda;
function makeLambda(param: string, body: Term): Lambda;
function makeLambda(
resolveOrParam: ((p: Term) => LambdaLike) | string,
maybeBody?: Term,
) {
super();
this._resolve = typeof resolveOrParam === 'function' ? resolveOrParam : () => new Undef();
this._param = typeof resolveOrParam === 'string' ? resolveOrParam : null;
this._body = maybeBody ?? null;
}
private _resolve: (p: Ref) => Term;
public get resolve(): (p: Ref) => Term {
return this._resolve;
}
private _param: string | null = null;
public get param(): string {
return this._param ??= this.resolve.toString().split(' ')[0];
}
private _body: Term | null = null;
public get body(): Term {
return this._body ??= this.resolve(new Ref('local', this.param));
}
public override refs(name: string): boolean {
return this.param !== name && this.body.refs(name);
}
public override bound(name: string): boolean {
return this.param !== name && this.body.bound(name);
}
public override get bindings(): Record<string, Term> {
return this.body.bindings;
}
public override bind(name: string, term: Term): Term {
return this.bound(name) || !this.refs(name)
? this
: new Lambda(this.param, this.body.bind(name, term));
}
public override expression(): string {
return this.body instanceof Lambda
? `\\ ${this.param} ${this.body.expression().slice(2)}`
: `\\ ${this.param} . ${this.body.expression()}`;
}
}
export class Call extends Term {
public constructor(
public func: Term,
public arg: Term,
) { super(); }
public override refs(name: string): boolean {
return this.func.refs(name) || this.arg.refs(name);
}
public override bound(name: string): boolean {
return this.func.bound(name) || this.arg.bound(name);
}
override get bindings(): Record<string, Term> {
return { ...this.func.bindings, ...this.arg.bindings };
}
public override bind(name: string, term: Term): Term {
return this.bound(name) || !this.refs(name)
? this
: new Call(this.func.bind(name, term), this.arg.bind(name, term));
}
public override reduce(): Term {
return this.cache = withLog(
`Reducing ${this.stringify()}`,
): Lambda {
const resolve: (p: Term) => LambdaLike = typeof resolveOrParam === 'function' ? resolveOrParam : makeUndef;
let param: string | null = typeof resolveOrParam === 'string' ? resolveOrParam : null;
let body: Term | null = maybeBody ?? null;
const term: Lambda = Object.assign(makeTerm(), {
type: 'L' as const,
param: () => param ??= resolve.toString().split(' ')[0],
body: () => body ??= _l(resolve(makeRef('local', term.param()))),
refs: (n: string) => term.param() !== n && term.body().refs(n),
bound: (n: string) => term.param() !== n && term.body().bound(n),
bindings: () => term.body().bindings(),
bind: (n: string, t: Term) => term.bound(n) || !term.refs(n)
? term
: makeLambda(term.param(), term.body().bind(n, t)),
expression: () => term.body().type === 'L'
? `\\ ${term.param()} ${term.body().expression().slice(2)}`
: `\\ ${term.param()} . ${term.body().expression()}`,
});
return term;
}
interface Call extends TermBase {
type: 'C';
}
function makeCall(func: Term, arg: Term): Call {
const term: Call = Object.assign(makeTerm(), {
type: 'C' as const,
refs: (n: string) => func.refs(n) || arg.refs(n),
bound: (n: string) => func.bound(n) || arg.bound(n),
bindings: () => ({ ...func.bindings, ...arg.bindings }),
bind: (n: string, t: Term) => term.bound(n) || !term.refs(n)
? term
: makeCall(func.bind(n, t), arg.bind(n, t)),
reduce: () => term.cache = withLog(
`Reducing ${term.stringify()}`,
() => withProfile(
this,
term,
'call',
() => {
if (this.cache) {
return this.cache;
if (term.cache) {
return term.cache;
}
const func = this.func.reduce();
if (!(func instanceof Lambda)) {
return new Undef();
const rf = func.reduce();
if (rf.type !== 'L') {
return makeUndef();
}
const l = rf as Lambda;
return withLog(
`Binding ${this.arg.stringify()} to ${func.param}`,
`Binding ${arg.stringify()} to ${l.param()}`,
() => simpleWithProfile(
`${func.param} = ${this.arg}`,
`${l.param()} = ${arg}`,
{ cat: 'binding' },
() => func.body.bind(func.param, this.arg),
() => l.body().bind(l.param(), arg),
),
r => `got ${r.stringify()}`,
).reduce();
},
),
r => `to ${r.stringify()}`,
);
),
expression: () => `${func.type === 'L' ? `(${func.expression()})` : func.expression()} ${arg.type === 'L' || arg.type === 'C' ? `(${arg.expression()})` : arg.expression()}`,
});
return term;
}
public override expression(): string {
return `${this.func instanceof Lambda ? `(${this.func.expression()})` : this.func.expression()} ${this.arg instanceof Lambda || this.arg instanceof Call ? `(${this.arg.expression()})` : this.arg.expression()}`;
}
}
export type Term = Undef | Native | Deferred | Ref | Lambda | Call;
const globals: Record<string, Term> = {};
@ -285,30 +222,36 @@ let namespace: string = 'core';
export const n = (name: string) => namespace = name;
export const g = (name: string, term: Term) => {
export const g = (name: string, term: LambdaLike) => {
const full = `${namespace}::${name}`;
if (globals[full]) {
throw new Error(`Duplicate global: "${full}"`);
}
globals[full] = term;
return new Ref(namespace, name);
globals[full] = isTerm(term) ? term : _l(term);
return makeRef(namespace, name);
};
export const _l = (f: (p: Ref) => Term) => new Lambda(f);
type LambdaLike =
| ((p0: Ref) => Term)
| ((p0: Ref) => (p1: Ref) => Term)
| ((p0: Ref) => (p1: Ref) => (p2: Ref) => Term)
| ((p0: Ref) => (p1: Ref) => (p2: Ref) => (p3: Ref) => Term);
export const _l = (f: LambdaLike) => isTerm(f) ? f : makeLambda(f);
type Deferedify = {
(value: (bindings: Record<string, Term>) => Term): Deferred
(value: boolean | number | string | object): Native
(value: (bindings: Record<string, Term>) => Term): Term;
(value: boolean | number | string | object): Term;
};
export const _: Deferedify = ((value: any) => typeof value === 'function' ? new Deferred(value) : new Native(value)) as Deferedify;
export const _: Deferedify = ((value: any) => typeof value === 'function' ? makeDeferred(value) : makeNative(value)) as Deferedify;
export const $ = <T>(t: Term): T => {
const rt = t.reduce();
return rt instanceof Native ? rt.value : rt.stringify();
return rt.type === 'N' ? rt.value : rt.stringify();
};
export const undef = g('undef', new Undef());
export const undef = g('undef', makeUndef());
export const id = g('id', _l(f => f));
export const cnst = g('cnst', _l(x => _l(_ => x)));
export const pipe = g('pipe', _l(f => _l(g => _l(x => f._(g._(x))))));
export const id = g('id', f => f);
export const cnst = g('cnst', x => _ => x);
export const pipe = g('pipe', f => g => x => f(g(x)));

@ -1,14 +1,16 @@
import { run } from './bf';
import { dump, log, profile } from './debug';
import { _ } from './core';
import { fromNumber, mul, toNumber } from './byte';
import { fromString, toString } from './string';
log();
profile();
const program = mul._(fromNumber(1))._(fromNumber(10));
const program = run
._(fromString('+'))
._(fromString(''));
try {
console.log(program.stringify(), ' -> ', toNumber(program));
console.log(program.stringify(), ' -> ', toString(program));
} finally {
dump();
}

@ -4,4 +4,4 @@ import { fromString as _s, cons, snoc } from './string';
n('list.show');
export const show = g('show', _l(eshow => _l(xs => concat._(snoc._(cons._(_s('['))._(intersperse._(_s(', '))._(map._(eshow)._(xs))))._(_s(']'))))));
export const show = g('show', eshow => xs => concat(snoc(cons(_s('['))(intersperse(_s(', '))(map(eshow)(xs))))(_s(']'))));

@ -5,68 +5,68 @@ import { Zero, succ } from './num';
n('list');
export const Nil = g('Nil', _l(z => _l(_ => z)));
export const Nil = g('Nil', z => _ => z);
export const Cons = g('Cons', _l(x => _l(xs => _l(_ => _l(f => f._(x)._(xs))))));
export const Cons = g('Cons', x => xs => _ => f => f(x)(xs));
export const cons = g('cons', Cons);
export const snoc = g('snoc', _l(xs => _l(x => xs._(cons._(x)._(Nil))._(_l(y => _l(ys => cons._(y)._(snoc._(ys)._(x))))))));
export const snoc = g('snoc', xs => x => xs(cons(x)(Nil))(y => ys => cons(y)(snoc(ys)(x))));
export const nul = g('nul', _l(xs => xs._(True)._(cnst._(cnst._(False)))));
export const nul = g('nul', xs => xs(True)(cnst(cnst(False))));
export const len = g('len', _l(xs => xs._(Zero)._(cnst._(pipe._(succ)._(len)))));
export const len = g('len', xs => xs(Zero)(cnst(pipe(succ)(len))));
export const singleton = g('singleton', _l(x => cons._(x)._(Nil)));
export const singleton = g('singleton', x => cons(x)(Nil));
export const append = g('append', _l(l => _l(r => l._(r)._(_l(x => _l(xs => cons._(x)._(append._(xs)._(r))))))));
export const append = g('append', l => r => l(r)(x => xs => cons(x)(append(xs)(r))));
export const concat = g('concat', _l(ls => ls._(Nil)._(_l(x => pipe._(append._(x))._(concat)))));
export const concat = g('concat', ls => ls(Nil)(x => pipe(append(x))(concat)));
export const repeat = g('repeat', _l(x => cons._(x)._(repeat._(x))));
export const repeat = g('repeat', x => cons(x)(repeat(x)));
export const iterate = g('iterate', _l(f => _l(x => cons._(x)._(iterate._(f)._(f._(x))))));
export const iterate = g('iterate', f => x => cons(x)(iterate(f)(f(x))));
export const head = g('head', _l(xs => xs._(undef)._(cnst)));
export const head = g('head', xs => xs(undef)(cnst));
export const tail = g('tail', _l(xs => xs._(undef)._(cnst._(id))));
export const tail = g('tail', xs => xs(undef)(cnst(id)));
export const foldl = g('foldl', _l(f => _l(z => _l(xs => xs._(z)._(pipe._(foldl._(f))._(f._(z)))))));
export const foldl = g('foldl', f => z => xs => xs(z)(pipe(foldl(f))(f(z))));
export const foldlz = g('foldlz', _l(f => _l(xs => xs._(undef)._(foldl._(f)))));
export const foldlz = g('foldlz', f => xs => xs(undef)(foldl(f)));
export const foldr = g('foldr', _l(f => _l(z => _l(xs => xs._(z)._(_l(x => pipe._(f._(x))._(foldr._(f)._(z))))))));
export const foldr = g('foldr', f => z => xs => xs(z)(x => pipe(f(x))(foldr(f)(z))));
export const foldrz = g('foldrz', undef);
export const cmp = g('cmp', _l(ecmp => _l(l => _l(r => l._(r._(EQ)._(cnst._(cnst._(LT))))._(_l(lx => _l(lxs => r._(GT)._(_l(rx => _l(rxs => iif._(eqc._(EQ)._(ecmp._(lx)._(rx)))._(cmp._(ecmp)._(lxs)._(rxs))._(ecmp._(lx)._(rx))))))))))));
export const cmp = g('cmp', ecmp => l => r => l(r(EQ)(cnst(cnst(LT))))(lx => lxs => r(GT)(rx => rxs => iif(eqc(EQ)(ecmp(lx)(rx)))(cmp(ecmp)(lxs)(rxs))(ecmp(lx)(rx)))));
export const lt = g('lt', _l(ecmp => _l(l => _l(r => r._(False)._(_l(rx => _l(rxs => l._(True)._(_l(lx => _l(lxs => ecmp._(lx)._(rx)._(True)._(lt._(ecmp)._(lxs)._(rxs))._(False)))))))))));
export const lt = g('lt', ecmp => l => r => r(False)(rx => rxs => l(True)(lx => lxs => ecmp(lx)(rx)(True)(lt(ecmp)(lxs)(rxs))(False))));
export const le = g('le', _l(ecmp => _l(l => _l(r => l._(True)._(_l(lx => _l(lxs => r._(False)._(_l(rx => _l(rxs => ecmp._(lx)._(rx)._(True)._(le._(ecmp)._(lxs)._(rxs))._(False)))))))))));
export const le = g('le', ecmp => l => r => l(True)(lx => lxs => r(False)(rx => rxs => ecmp(lx)(rx)(True)(le(ecmp)(lxs)(rxs))(False))));
export const eq = g('eq', _l(eeq => _l(l => _l(r => l._(r._(True)._(cnst._(cnst._(False))))._(_l(lx => _l(lxs => r._(False)._(_l(rx => _l(rxs => and._(eeq._(lx)._(rx))._(eq._(eeq)._(lxs)._(rxs))))))))))));
export const eq = g('eq', eeq => l => r => l(r(True)(cnst(cnst(False))))(lx => lxs => r(False)(rx => rxs => and(eeq(lx)(rx))(eq(eeq)(lxs)(rxs)))));
export const ge = g('ge', _l(ecmp => _l(l => _l(r => r._(True)._(_l(rx => _l(rxs => l._(False)._(_l(lx => _l(lxs => ecmp._(lx)._(rx)._(False)._(ge._(ecmp)._(lxs)._(rxs))._(True)))))))))));
export const ge = g('ge', ecmp => l => r => r(True)(rx => rxs => l(False)(lx => lxs => ecmp(lx)(rx)(False)(ge(ecmp)(lxs)(rxs))(True))));
export const gt = g('gt', _l(ecmp => _l(l => _l(r => l._(False)._(_l(lx => _l(lxs => r._(True)._(_l(rx => _l(rxs => ecmp._(lx)._(rx)._(False)._(gt._(ecmp)._(lxs)._(rxs))._(True)))))))))));
export const gt = g('gt', ecmp => l => r => l(False)(lx => lxs => r(True)(rx => rxs => ecmp(lx)(rx)(False)(gt(ecmp)(lxs)(rxs))(True))));
export const map = g('map', _l(f => _l(xs => xs._(Nil)._(_l(x => pipe._(cons._(f._(x)))._(map._(f)))))));
export const map = g('map', f => xs => xs(Nil)(x => pipe(cons(f(x)))(map(f))));
export const filter = g('filter', _l(f => _l(xs => xs._(Nil)._(_l(x => pipe._(iif._(f._(x))._(cons._(x))._(id))._(filter._(f)))))));
export const filter = g('filter', f => xs => xs(Nil)(x => pipe(iif(f(x))(cons(x))(id))(filter(f))));
export const any = g('any', _l(f => _l(xs => xs._(False)._(_l(x => pipe._(or._(f._(x)))._(any._(f)))))));
export const any = g('any', f => xs => xs(False)(x => pipe(or(f(x)))(any(f))));
export const all = g('all', _l(f => _l(xs => xs._(True)._(_l(x => pipe._(and._(f._(x)))._(all._(f)))))));
export const all = g('all', f => xs => xs(True)(x => pipe(and(f(x)))(all(f))));
export const get = g('get', _l(i => _l(xs => xs._(undef)._(_l(x => i._(cnst._(x))._(get))))));
export const get = g('get', i => xs => xs(undef)(x => i(cnst(x))(get)));
export const update = g('update', _l(f => _l(i => _l(xs => xs._(undef)._(_l(x => _l(xs => i._(cons._(f._(x))._(xs))._(_l(pi => cons._(x)._(update._(f)._(pi)._(xs)))))))))));
export const update = g('update', f => i => xs => xs(undef)(x => xs => i(cons(f(x))(xs))(pi => cons(x)(update(f)(pi)(xs)))));
export const set = g('set', pipe._(update)._(cnst));
export const set = g('set', pipe(update)(cnst));
export const intersperse = g('intersperse', _l(v => _l(xs => xs._(xs)._(_l(x => _l(rxs => rxs._(xs)._(cnst._(cnst._(cons._(x)._(cons._(v)._(intersperse._(v)._(rxs))))))))))));
export const intersperse = g('intersperse', v => xs => xs(xs)(x => rxs => rxs(xs)(cnst(cnst(cons(x)(cons(v)(intersperse(v)(rxs))))))));
export const fromArray: (xs: Term[]) => Term = xs => !xs.length ? Nil : Cons._(xs[0])._(_(() => fromArray(xs.slice(1))));
export const fromArray: (xs: Term[]) => Term = xs => !xs.length ? Nil : Cons(xs[0])(_(() => fromArray(xs.slice(1))));
export const toArray: (xs: Term) => Term[] = xs => $(xs._(_([]))._(_l(x => _l(xs => _(({ x, xs }) => _([x, ...toArray(xs)]))))));
export const toArray: (xs: Term) => Term[] = xs => $(xs(_([]))(x => xs => _(({ x, xs }) => _([x, ...toArray(xs)]))));

@ -1,7 +1,7 @@
import { _, _l } from './core';
import { toString } from './string';
export const log = _l(s => _l(p => _(({ s, p }) => {
export const log = _l(s => p => _(({ s, p }) => {
console.log(toString(s));
return p;
})));
}));

@ -6,4 +6,4 @@ import { Empty, append, cons } from './string';
n('num.show');
export const show = g('show', _l(n => iif._(lt._(n)._(_n(10)))._(cons._(char._(sum._(n)._(_n(48))))._(Empty))._(append._(show._(div._(n)._(_n(10))))._(show._(mod._(n)._(_n(10)))))));
export const show = g('show', n => iif(lt(n)(_n(10)))(cons(char(sum(n)(_n(48))))(Empty))(append(show(div(n)(_n(10))))(show(mod(n)(_n(10))))));

@ -4,42 +4,42 @@ import { False, True, iif } from './bool';
n('num');
export const Zero = g('Zero', _l(z => _l(_ => z)));
export const Zero = g('Zero', z => _ => z);
export const Succ = g('Succ', _l(p => _l(_ => _l(n => n._(p)))));
export const Succ = g('Succ', p => _ => n => n(p));
export const ifz = g('ifz', _l(n => _l(t => _l(f => n._(t)._(cnst._(f))))));
export const ifz = g('ifz', n => t => f => n(t)(cnst(f)));
export const succ = g('succ', Succ);
export const pred = g('pred', _l(n => n._(Zero)._(id)));
export const pred = g('pred', n => n(Zero)(id));
export const cmp = g('cmp', _l(l => _l(r => l._(r._(EQ)._(cnst._(LT)))._(pipe._(r._(GT))._(cmp)))));
export const cmp = g('cmp', l => r => l(r(EQ)(cnst(LT)))(pipe(r(GT))(cmp)));
export const lt = g('lt', _l(l => _l(r => r._(False)._(l._(cnst._(True))._(lt)))));
export const lt = g('lt', l => r => r(False)(l(cnst(True))(lt)));
export const le = g('le', _l(l => _l(r => l._(True)._(r._(cnst._(False))._(ge)))));
export const le = g('le', l => r => l(True)(r(cnst(False))(ge)));
export const eq = g('eq', _l(l => _l(r => l._(r._(True)._(cnst._(False)))._(r._(cnst._(False))._(eq)))));
export const eq = g('eq', l => r => l(r(True)(cnst(False)))(r(cnst(False))(eq)));
export const ge = g('ge', _l(l => _l(r => r._(True)._(l._(cnst._(False))._(ge)))));
export const ge = g('ge', l => r => r(True)(l(cnst(False))(ge)));
export const gt = g('gt', _l(l => _l(r => l._(False)._(r._(cnst._(True))._(lt)))));
export const gt = g('gt', l => r => l(False)(r(cnst(True))(lt)));
export const even = g('even', _l(n => n._(True)._(odd)));
export const even = g('even', n => n(True)(odd));
export const odd = g('odd', _l(n => n._(False)._(even)));
export const odd = g('odd', n => n(False)(even));
export const sum = g('sum', _l(l => _l(r => r._(l)._(sum._(Succ._(l))))));
export const sum = g('sum', l => r => r(l)(sum(Succ(l))));
export const sub = g('sub', _l(l => _l(r => r._(l)._(l._(cnst._(Zero))._(sub)))));
export const sub = g('sub', l => r => r(l)(l(cnst(Zero))(sub)));
export const mul = g('mul', _l(l => _l(r => l._(Zero)._(_l(pl => sum._(r)._(mul._(pl)._(r)))))));
export const mul = g('mul', l => r => l(Zero)(pl => sum(r)(mul(pl)(r))));
export const div = g('div', _l(l => _l(r => iif._(lt._(l)._(r))._(Zero)._(succ._(div._(sub._(l)._(r))._(r))))));
export const div = g('div', l => r => iif(lt(l)(r))(Zero)(succ(div(sub(l)(r))(r))));
export const mod = g('mod', _l(l => _l(r => iif._(lt._(l)._(r))._(l)._(mod._(sub._(l)._(r))._(r)))));
export const mod = g('mod', l => r => iif(lt(l)(r))(l)(mod(sub(l)(r))(r)));
export const fromNumber: (n: number) => Term = n => !n ? Zero : Succ._(_(() => fromNumber(n - 1)));
export const fromNumber: (n: number) => Term = n => !n ? Zero : Succ(_(() => fromNumber(n - 1)));
export const toNumber: (n: Term) => number = n => $(n._(_(0))._(_l(p => _(({ p }) => _(1 + toNumber(p))))));
export const toNumber: (n: Term) => number = n => $(n(_(0))(p => _(({ p }) => _(1 + toNumber(p)))));

@ -3,4 +3,4 @@ import { fromString as _s } from './string';
n('ord.show');
export const show = g('show', _l(o => o._(_s('LT'))._(_s('EQ'))._(_s('GT'))));
export const show = g('show', o => o(_s('LT'))(_s('EQ'))(_s('GT')));

@ -9,19 +9,19 @@ export const enum NOrd {
GT,
};
export const LT = g('LT', _l(lt => _l(_ => _l(_ => lt))));
export const LT = g('LT', lt => _ => _ => lt);
export const EQ = g('EQ', _l(_ => _l(eq => _l(_ => eq))));
export const EQ = g('EQ', _ => eq => _ => eq);
export const GT = g('GT', _l(_ => _l(_ => _l(gt => gt))));
export const GT = g('GT', _ => _ => gt => gt);
export const eq = g('eq', _l(l => _l(r => l
._(r._(True)._(False)._(False))
._(r._(False)._(True)._(False))
._(r._(False)._(False)._(True)))));
export const eq = g('eq', l => r => l
(r(True)(False)(False))
(r(False)(True)(False))
(r(False)(False)(True)));
export const fromNOrd: (o: NOrd) => Term
= o => o === NOrd.LT ? LT : o === NOrd.EQ ? EQ : GT;
export const toNOrd: (o: Term) => NOrd
= o => $(o._(_(NOrd.LT))._(_(NOrd.EQ))._(_(NOrd.GT)).reduce());
= o => $(o(_(NOrd.LT))(_(NOrd.EQ))(_(NOrd.GT)).reduce());

@ -5,4 +5,4 @@ import { fromString as _s } from './string';
n('pair.show');
export const show = g('show', _l(fshow => _l(sshow => uncurry._(_l(f => _l(s => concat._(cons._(_s('('))._(cons._(fshow._(f))._(cons._(_s(', '))._(cons._(sshow._(s))._(cons._(_s(')'))._(Nil))))))))))));
export const show = g('show', fshow => sshow => uncurry(f => s => concat(cons(_s('('))(cons(fshow(f))(cons(_s(', '))(cons(sshow(s))(cons(_s(')'))(Nil))))))));

@ -5,28 +5,28 @@ import { fromString as _s } from './string';
n('pair');
export const Pair = g('Pair', _l(f => _l(s => _l(p => p._(f)._(s)))));
export const Pair = g('Pair', f => s => p => p(f)(s));
export const fst = g('fst', _l(p => p._(_l(f => _l(_ => f)))));
export const fst = g('fst', p => p(f => _ => f));
export const snd = g('snd', _l(p => p._(_l(_ => _l(s => s)))));
export const snd = g('snd', p => p(_ => s => s));
export const first = g('first', _l(t => _l(p => p._(_l(f => _l(s => Pair._(t._(f))._(s)))))));
export const first = g('first', t => p => p(f => s => Pair(t(f))(s)));
export const second = g('second', _l(t => _l(p => p._(_l(f => _l(s => Pair._(f)._(t._(s))))))));
export const second = g('second', t => p => p(f => s => Pair(f)(t(s))));
export const both = g('both', _l(tf => _l(ts => _l(p => p._(_l(f => _l(s => Pair._(tf._(f))._(ts._(s)))))))));
export const both = g('both', tf => ts => p => p(f => s => Pair(tf(f))(ts(s))));
export const uncurry = g('uncurry', _l(t => _l(p => p._(t))));
export const uncurry = g('uncurry', t => p => p(t));
export const cmp = g('cmp', _l(fcmp => _l(scmp => uncurry._(_l(lf => _l(ls => uncurry._(_l(rf => _l(rs => fcmp._(lf)._(rf)._(LT)._(scmp._(ls)._(rs))._(GT))))))))));
export const cmp = g('cmp', fcmp => scmp => uncurry(lf => ls => uncurry(rf => rs => fcmp(lf)(rf)(LT)(scmp(ls)(rs))(GT))));
export const lt = g('lt', _l(fcmp => _l(scmp => uncurry._(_l(lf => _l(ls => uncurry._(_l(rf => _l(rs => fcmp._(lf)._(rf)._(True)._(scmp._(ls)._(rs)._(True)._(False)._(False))._(False))))))))));
export const lt = g('lt', fcmp => scmp => uncurry(lf => ls => uncurry(rf => rs => fcmp(lf)(rf)(True)(scmp(ls)(rs)(True)(False)(False))(False))));
export const le = g('le', _l(fcmp => _l(scmp => uncurry._(_l(lf => _l(ls => uncurry._(_l(rf => _l(rs => fcmp._(lf)._(rf)._(True)._(scmp._(ls)._(rs)._(True)._(True)._(False))._(False))))))))));
export const le = g('le', fcmp => scmp => uncurry(lf => ls => uncurry(rf => rs => fcmp(lf)(rf)(True)(scmp(ls)(rs)(True)(True)(False))(False))));
export const eq = g('eq', _l(feq => _l(seq => uncurry._(_l(lf => _l(ls => uncurry._(_l(rf => _l(rs => and._(feq._(lf)._(rf))._(seq._(ls)._(rs)))))))))));
export const eq = g('eq', feq => seq => uncurry(lf => ls => uncurry(rf => rs => and(feq(lf)(rf))(seq(ls)(rs)))));
export const ge = g('ge', _l(fcmp => _l(scmp => uncurry._(_l(lf => _l(ls => uncurry._(_l(rf => _l(rs => fcmp._(lf)._(rf)._(False)._(scmp._(ls)._(rs)._(False)._(True)._(True))._(True))))))))));
export const ge = g('ge', fcmp => scmp => uncurry(lf => ls => uncurry(rf => rs => fcmp(lf)(rf)(False)(scmp(ls)(rs)(False)(True)(True))(True))));
export const gt = g('gt', _l(fcmp => _l(scmp => uncurry._(_l(lf => _l(ls => uncurry._(_l(rf => _l(rs => fcmp._(lf)._(rf)._(False)._(scmp._(ls)._(rs)._(False)._(False)._(True))._(True))))))))));
export const gt = g('gt', fcmp => scmp => uncurry(lf => ls => uncurry(rf => rs => fcmp(lf)(rf)(False)(scmp(ls)(rs)(False)(False)(True))(True))));

@ -4,4 +4,4 @@ import { fromString as _s, wrap } from './string';
n('string.show');
export const show = g('show', wrap._(_s('"')));
export const show = g('show', wrap(_s('"')));

@ -10,20 +10,20 @@ export const Empty = g('Empty', Nil);
export const empty = g('empty', nul);
export const cmp = g('cmp', cmpl._(cmpc));
export const cmp = g('cmp', cmpl(cmpc));
export const lt = g('lt', ltl._(cmpc));
export const lt = g('lt', ltl(cmpc));
export const le = g('le', lel._(cmpc));
export const le = g('le', lel(cmpc));
export const eq = g('eq', eql._(eqc));
export const eq = g('eq', eql(eqc));
export const ge = g('ge', gel._(cmpc));
export const ge = g('ge', gel(cmpc));
export const gt = g('gt', gtl._(cmpc));
export const gt = g('gt', gtl(cmpc));
export const wrap = g('wrap', _l(w => _l(c => append._(w)._(append._(c)._(w)))));
export const wrap = g('wrap', w => c => append(w)(append(c)(w)));
export const fromString: (xs: string) => Term = s => !s.length ? Nil : Cons._(fromChar(s[0]))._(_(() => fromString(s.slice(1))));
export const fromString: (xs: string) => Term = s => !s.length ? Nil : Cons(fromChar(s[0]))(_(() => fromString(s.slice(1))));
export const toString: (xs: Term) => string = s => $(s._(_(''))._(_l(x => _l(xs => _(({ x, xs }) => _(toChar(x) + toString(xs)))))));
export const toString: (xs: Term) => string = s => $(s(_(''))(x => xs => _(({ x, xs }) => _(toChar(x) + toString(xs)))));

@ -16,7 +16,7 @@ describe('List', () => {
const _na: (xs: number[]) => Term = xs => !xs.length ? Nil : Cons._(_n(xs[0]))._(_(() => _na(xs.slice(1))));
const $na: (xs: Term) => number[] = xs => $(xs._(_([]))._(_l(x => _l(xs => _(({ x, xs }) => _([$n(x), ...$na(xs)]))))));
const $na: (xs: Term) => number[] = xs => $(xs._(_([]))._(x => xs => _(({ x, xs }) => _([$n(x), ...$na(xs)]))));
describe('toArray', () => {
it('converts []', () => {
@ -60,7 +60,7 @@ describe('List', () => {
});
it('handles infinite lists', () => {
expect($n(cons._(_n(0))._(infinite)._(undef)._(_l(x => _l(_ => x))))).toBe(0);
expect($n(cons._(_n(0))._(infinite)._(undef)._(x => _ => x))).toBe(0);
});
});
@ -78,7 +78,7 @@ describe('List', () => {
});
it('handles infinite lists', () => {
expect($n(snoc._(infinite)._(_n(0))._(undef)._(_l(x => _l(_ => x))))).toBe(0);
expect($n(snoc._(infinite)._(_n(0))._(undef)._(x => _ => x))).toBe(0);
});
});
@ -142,7 +142,7 @@ describe('List', () => {
});
it('handles infinite lists', () => {
expect($n(append._(infinite)._(infinite)._(undef)._(_l(x => _l(_ => x))))).toBe(0);
expect($n(append._(infinite)._(infinite)._(undef)._(x => _ => x))).toBe(0);
});
});
@ -161,7 +161,7 @@ describe('List', () => {
it('handles infinite lists', () => {
const dinfinite: Term = g('dinfinite', _(() => cons._(infinite)._(dinfinite)));
expect($n(concat._(dinfinite)._(undef)._(_l(x => _l(_ => x))))).toBe(0);
expect($n(concat._(dinfinite)._(undef)._(x => _ => x))).toBe(0);
});
});
@ -263,7 +263,7 @@ describe('List', () => {
it('handles infinite lists', () => {
expect($n(
foldr
._(_l(x => _l(a => sum._(x)._(iif._(eqn._(_n(5))._(x))._(Zero)._(a)))))
._(x => a => sum._(x)._(iif._(eqn._(_n(5))._(x))._(Zero)._(a)))
._(Zero)
._(infinite)))
.toBe(15);
@ -286,7 +286,7 @@ describe('List', () => {
it.failing('handles infinite lists', () => {
expect($n(
foldrz
._(_l(x => _l(a => sum._(x)._(iif._(eqn._(_n(5))._(x))._(Zero)._(a)))))
._(x => a => sum._(x)._(iif._(eqn._(_n(5))._(x))._(Zero)._(a)))
._(infinite)))
.toBe(15);
});

@ -108,7 +108,7 @@ describe('String', () => {
});
it('handles infinite strings', () => {
expect($c(append._(infinite)._(infinite)._(undef)._(_l(x => _l(_ => x))))).toBe('a');
expect($c(append._(infinite)._(infinite)._(undef)._(x => _ => x))).toBe('a');
});
});
@ -122,7 +122,7 @@ describe('String', () => {
});
it('handles infinite strings', () => {
expect($c(wrap._(infinite)._(infinite)._(undef)._(_l(x => _l(_ => x))))).toBe('a');
expect($c(wrap._(infinite)._(infinite)._(undef)._(x => _ => x))).toBe('a');
});
});

Loading…
Cancel
Save