Lazy lambda creation

master
Freywar Ulvnaudgari 2 years ago
parent 084399c6b4
commit e7010aaeb0
  1. 10
      src/bf.ts
  2. 8
      src/byte.ts
  3. 41
      src/core.ts
  4. 44
      src/list.ts
  5. 4
      src/num.show.ts
  6. 26
      src/num.ts
  7. 9
      src/ord.ts
  8. 4
      test/list.spec.ts
  9. 4
      test/num.spec.ts
  10. 4
      test/string.spec.ts

@ -1,4 +1,4 @@
import { _, _l, cnst, g, id, n, pipe, _r } from './core';
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';
@ -36,15 +36,15 @@ const next = g('next', second._(first._(first._(succ))));
const prev = g('prev', second._(first._(first._(pred))));
const jump = g('jump', _l(d => _l(s =>
iif._(command._(_c('['))._(s))._(_r('bf', 'jump')._(succ._(d)))
._(iif._(command._(_c(']'))._(s))._(ifz._(pred._(d))._(cnst._(s))._(_r('bf', 'jump')._(pred._(d))))
._(_r('bf', 'jump')._(d)))._(advance._(s)))));
iif._(command._(_c('['))._(s))._(jump._(succ._(d)))
._(iif._(command._(_c(']'))._(s))._(ifz._(pred._(d))._(cnst._(s))._(jump._(pred._(d))))
._(jump._(d)))._(advance._(s)))));
const whlnz = g('whlnz', _l(s => ifn._(read._(s))._(jump._(Zero))._(save)._(s)));
const endwhl = g('endwhl', _l(s => ifn._(read._(s))._(reset)._(pipe._(save)._(restore))._(s)));
const exec = g('exec', _l(s => iif._(done._(s))._(s)._(_r('bf', 'exec')._(advance
const exec = g('exec', _l(s => iif._(done._(s))._(s)._(exec._(advance
._(iif._(command._(_c('>'))._(s))._(next)
._(iif._(command._(_c('<'))._(s))._(prev)
._(iif._(command._(_c('+'))._(s))._(inc)

@ -1,4 +1,4 @@
import { Term, _, _l, g, id, n, _r as ref } from './core';
import { Term, _, _l, g, id, n } from './core';
import { iif } from './bool';
import { Succ, Zero, fromNumber as _n, eq } from './num';
@ -16,10 +16,10 @@ export const inc = g('inc', Inc);
export const dec = g('dec', _l(n => n._(xFF)._(id)));
export const sum = g('sum', _l(l => _l(r => r._(l)._(ref('byte', 'sum')._(inc._(l))))));
export const sum = g('sum', _l(l => _l(r => r._(l)._(sum._(inc._(l))))));
export const sub = g('sub', _l(l => _l(r => r._(l)._(ref('byte', 'sub')._(dec._(l))))));
export const sub = g('sub', _l(l => _l(r => r._(l)._(sub._(dec._(l))))));
export const mul = g('mul', _l(l => _l(r => l._(x00)._(_l(pl => sum._(r)._(ref('byte', 'mul')._(pl)._(r)))))));
export const mul = g('mul', _l(l => _l(r => l._(x00)._(_l(pl => sum._(r)._(mul._(pl)._(r)))))));
export const fromNumber: (n: number) => Term = n => _n(n % 256);

@ -63,15 +63,6 @@ export abstract class Term {
}
}
type Termify = {
(term: Term): Term
(name: string): Term
(namespace: string, name: string): Term
};
const termify: Termify = (termOrNameOrNamespace: Term | string, maybeName?: string) =>
typeof termOrNameOrNamespace === 'string' ? _r(termOrNameOrNamespace as string, maybeName as string) : termOrNameOrNamespace;
export class Undef extends Term {
constructor() { super(); }
@ -178,10 +169,32 @@ export class Ref extends Term {
}
export class Lambda extends Term {
public constructor(resolve: (p: Ref) => Term);
public constructor(param: string, body: Term);
public constructor(
public param: string,
public body: Term,
) { super(); }
resolveOrParam: ((p: Ref) => Term) | 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);
@ -281,9 +294,7 @@ export const g = (name: string, term: Term) => {
return new Ref(namespace, name);
};
export const _r = (ns: string, name: string) => new Ref(ns, name);
export const _l = (f: (p: Ref) => Term) => new Lambda(f.toString().split(' ')[0], f(new Ref('local', f.toString().split(' ')[0])));
export const _l = (f: (p: Ref) => Term) => new Lambda(f);
type Deferedify = {
(value: (bindings: Record<string, Term>) => Term): Deferred

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

@ -1,8 +1,8 @@
import { _, _l, g, n, _r } from './core';
import { _, _l, g, n } from './core';
import { iif } from './bool';
import { fromNumber as _n, div, lt, mod, sum } from './num';
import { Empty, append, cons } from './string';
n('num.show');
export const show = g('show', _l(n => iif._(lt._(n)._(_n(10)))._(cons._(sum._(n)._(_n(48)))._(Empty))._(append._(_r('num.show', 'show')._(div._(n)._(_n(10))))._(_r('num.show', 'show')._(mod._(n)._(_n(10)))))));
export const show = g('show', _l(n => iif._(lt._(n)._(_n(10)))._(cons._(sum._(n)._(_n(48)))._(Empty))._(append._(show._(div._(n)._(_n(10))))._(show._(mod._(n)._(_n(10)))))));

@ -1,4 +1,4 @@
import { $, Term, _, _l, cnst, g, id, n, pipe, _r as ref } from './core';
import { $, Term, _, _l, cnst, g, id, n, pipe } from './core';
import { EQ, GT, LT } from './ord';
import { False, True, iif } from './bool';
@ -14,31 +14,31 @@ export const succ = g('succ', Succ);
export const pred = g('pred', _l(n => n._(Zero)._(id)));
export const cmp = g('cmp', _l(l => _l(r => l._(r._(EQ)._(cnst._(LT)))._(pipe._(r._(GT))._(ref('num', 'cmp'))))));
export const cmp = g('cmp', _l(l => _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))._(ref('num', 'lt'))))));
export const lt = g('lt', _l(l => _l(r => r._(False)._(l._(cnst._(True))._(lt)))));
export const le = g('le', _l(l => _l(r => l._(True)._(r._(cnst._(False))._(ref('num', 'ge'))))));
export const le = g('le', _l(l => _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))._(ref('num', 'eq'))))));
export const eq = g('eq', _l(l => _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))._(ref('num', 'ge'))))));
export const ge = g('ge', _l(l => _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 even = g('even', _l(n => n._(True)._(ref('num', 'odd'))));
export const even = g('even', _l(n => n._(True)._(odd)));
export const odd = g('odd', _l(n => n._(False)._(ref('num', 'even'))));
export const odd = g('odd', _l(n => n._(False)._(even)));
export const sum = g('sum', _l(l => _l(r => r._(l)._(ref('num', 'sum')._(Succ._(l))))));
export const sum = g('sum', _l(l => _l(r => r._(l)._(sum._(Succ._(l))))));
export const sub = g('sub', _l(l => _l(r => r._(l)._(l._(cnst._(Zero))._(ref('num', 'sub'))))));
export const sub = g('sub', _l(l => _l(r => r._(l)._(l._(cnst._(Zero))._(sub)))));
export const mul = g('mul', _l(l => _l(r => l._(Zero)._(_l(pl => sum._(r)._(ref('num', 'mul')._(pl)._(r)))))));
export const mul = g('mul', _l(l => _l(r => l._(Zero)._(_l(pl => sum._(r)._(mul._(pl)._(r)))))));
export const div = g('div', _l(l => _l(r => iif._(lt._(l)._(r))._(Zero)._(succ._(ref('num', 'div')._(sub._(l)._(r))._(r))))));
export const div = g('div', _l(l => _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)._(ref('num', 'mod')._(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 fromNumber: (n: number) => Term = n => !n ? Zero : Succ._(_(() => fromNumber(n - 1)));

@ -1,4 +1,5 @@
import { $, Term, _, _l, g, n, _r as ref } from './core';
import { $, Term, _, _l, g, n } from './core';
import { False, True } from './bool';
n('ord');
@ -15,9 +16,9 @@ export const EQ = g('EQ', _l(_ => _l(eq => _l(_ => eq))));
export const GT = g('GT', _l(_ => _l(_ => _l(gt => gt))));
export const eq = g('eq', _l(l => _l(r => l
._(r._(ref('bool', 'True'))._(ref('bool', 'False'))._(ref('bool', 'False')))
._(r._(ref('bool', 'False'))._(ref('bool', 'True'))._(ref('bool', 'False')))
._(r._(ref('bool', 'False'))._(ref('bool', 'False'))._(ref('bool', 'True'))))));
._(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;

@ -1,5 +1,5 @@
import { describe, expect, it } from '@jest/globals';
import { $, Term, _, _l, g, n, undef, _r as ref } from '../src/core';
import { $, Term, _, _l, g, n, undef } from '../src/core';
import { toNOrd as $o, NOrd } from '../src/ord';
import { toBoolean as $b, iif } from '../src/bool';
import { toNumber as $n, Succ, Zero, fromNumber as _n, fromNumber as _nn, cmp as cmpn, eq as eqn, even, gt as ngt, odd, succ, sum } from '../src/num';
@ -160,7 +160,7 @@ describe('List', () => {
});
it('handles infinite lists', () => {
const dinfinite: Term = g('dinfinite', cons._(infinite)._(ref('list.spec', 'dinfinite')));
const dinfinite: Term = g('dinfinite', _(() => cons._(infinite)._(dinfinite)));
expect($n(concat._(dinfinite)._(undef)._(_l(x => _l(_ => x))))).toBe(0);
});
});

@ -1,5 +1,5 @@
import { describe, expect, it } from '@jest/globals';
import { Term, _, g, n, _r, undef } from '../src/core';
import { Term, _, g, n, 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 $n, Succ, Zero, fromNumber as _n, cmp, div, eq, ge, gt, ifz, le, lt, mod, mul, pred, sub, succ, sum } from '../src/num';
@ -9,7 +9,7 @@ import { show } from '../src/num.show';
n('num.spec');
describe('Num', () => {
const infinity: Term = g('infinity', _(() => Succ._(_r('num.spec', 'infinity'))));
const infinity: Term = g('infinity', _(() => Succ._(infinity)));
describe('toNumber', () => {
it('converts 0', () => {

@ -1,5 +1,5 @@
import { describe, expect, it } from '@jest/globals';
import { Term, _, _l, g, n, undef, _r as ref } from '../src/core';
import { Term, _, _l, g, n, undef } from '../src/core';
import { NOrd, toNOrd } from '../src/ord';
import { toBoolean as $b } from '../src/bool';
import { toNumber as $n, Zero, gt as ngt } from '../src/num';
@ -10,7 +10,7 @@ import { show } from '../src/string.show';
n('string.spec');
describe('String', () => {
const infinite: Term = g('infinite', Cons._(_c('a'))._(ref('string.spec', 'infinite')));
const infinite: Term = g('infinite', _(() => Cons._(_c('a'))._(infinite)));
describe('toString', () => {
it('converts ""', () => {

Loading…
Cancel
Save