diff --git a/eslint.config.mjs b/eslint.config.mjs index 5326b90..c219277 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -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', { diff --git a/profile.json b/profile.json new file mode 100644 index 0000000..f3b27be --- /dev/null +++ b/profile.json @@ -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`"}}]} \ No newline at end of file diff --git a/src/bf.ts b/src/bf.ts index cc147b9..bf9e697 100644 --- a/src/bf.ts +++ b/src/bf.ts @@ -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)))))))); diff --git a/src/bool.show.ts b/src/bool.show.ts index 0f3d2b3..2890138 100644 --- a/src/bool.show.ts +++ b/src/bool.show.ts @@ -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'))); diff --git a/src/bool.ts b/src/bool.ts index 2b0289a..162d5cd 100644 --- a/src/bool.ts +++ b/src/bool.ts @@ -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()); diff --git a/src/byte.show.ts b/src/byte.show.ts index c94d390..721ad72 100644 --- a/src/byte.show.ts +++ b/src/byte.show.ts @@ -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))); diff --git a/src/byte.ts b/src/byte.ts index 4f5d89c..bc783fb 100644 --- a/src/byte.ts +++ b/src/byte.ts @@ -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)); diff --git a/src/char.show.ts b/src/char.show.ts index aa0f04b..6ccfcb0 100644 --- a/src/char.show.ts +++ b/src/char.show.ts @@ -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)); diff --git a/src/core.ts b/src/core.ts index fd3f979..669cc55 100644 --- a/src/core.ts +++ b/src/core.ts @@ -12,303 +12,246 @@ 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 { - return {}; - } - - public bind(_name: string, _term: Term): Term { - return this; - } - - public reduce(): Term { - return this; - } - - public context(): string { - return `#${this.id}${this.cache ? '' : ''}${!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()}>`; - } +interface TermBase { + type: string; + id: number; + cache: Term | null; + refs(name: string): boolean; + bound(name: string): boolean; + bindings(): Record; + bind(name: string, term: Term): Term; + reduce(): Term; + context(): string; + expression(): string; + stringify(): string; + _(arg: LambdaLike): Term; + (arg: LambdaLike): Term; } -export class Undef extends Term { - constructor() { super(); } - - override reduce(): Term { - throw new Error('undef'); - } +function isTerm(value: any): value is Term { + return value && value.type; } -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(); - } +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 ? '' : ''}${!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; } -export class Deferred extends Term { - public constructor( - protected func: (bindings: Record) => Term, - protected _bindings: Record = {}, - ) { super(); } +interface Undef extends TermBase { + type: 'undef'; +} - public override refs(_name: string): boolean { - return true; - } +function makeUndef(): Undef { + const term: Undef = Object.assign(makeTerm(), { + type: 'undef' as const, + reduce: () => { + throw new Error('undef'); + }, + }); + 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 { - 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) => Term, bindings: Record = {}): 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`'; - } + ), + }); + return term; } -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 { - return this.binding ? { [this.name]: this.binding } : {}; - } - - 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()}`, - ); - } - - public override expression(): string { - return this.name; - } + ), + expression: () => name, + }); + return 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, - 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 { - 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()}`; - } +interface Lambda extends TermBase { + type: 'L'; + param(): string; + body(): Term; } -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 { - return { ...this.func.bindings, ...this.arg.bindings }; - } +function makeLambda(resolve: (p: Term) => LambdaLike): Lambda; +function makeLambda(param: string, body: Term): Lambda; +function makeLambda( + resolveOrParam: ((p: Term) => LambdaLike) | string, + maybeBody?: Term, +): 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; +} - 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)); - } +interface Call extends TermBase { + type: 'C'; +} - public override reduce(): Term { - return this.cache = withLog( - `Reducing ${this.stringify()}`, +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()}`, - ); - } - - 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()}`; - } + ), + expression: () => `${func.type === 'L' ? `(${func.expression()})` : func.expression()} ${arg.type === 'L' || arg.type === 'C' ? `(${arg.expression()})` : arg.expression()}`, + }); + return term; } +export type Term = Undef | Native | Deferred | Ref | Lambda | Call; + const globals: Record = {}; 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) => Term): Deferred - (value: boolean | number | string | object): Native + (value: (bindings: Record) => 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: 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))); diff --git a/src/index.ts b/src/index.ts index b8db7e5..3c25ee6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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(); } diff --git a/src/list.show.ts b/src/list.show.ts index e593cba..3febf14 100644 --- a/src/list.show.ts +++ b/src/list.show.ts @@ -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(']')))); diff --git a/src/list.ts b/src/list.ts index 9d9a3a1..9dff17b 100644 --- a/src/list.ts +++ b/src/list.ts @@ -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)])))); diff --git a/src/log.ts b/src/log.ts index 8b53c7c..84421d6 100644 --- a/src/log.ts +++ b/src/log.ts @@ -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; -}))); +})); diff --git a/src/num.show.ts b/src/num.show.ts index feadd6b..a8478ac 100644 --- a/src/num.show.ts +++ b/src/num.show.ts @@ -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)))))); diff --git a/src/num.ts b/src/num.ts index 87d5686..c7f1c5d 100644 --- a/src/num.ts +++ b/src/num.ts @@ -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))))); diff --git a/src/ord.show.ts b/src/ord.show.ts index 85b0282..7d65d4b 100644 --- a/src/ord.show.ts +++ b/src/ord.show.ts @@ -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'))); diff --git a/src/ord.ts b/src/ord.ts index 07d2a32..fc9d98e 100644 --- a/src/ord.ts +++ b/src/ord.ts @@ -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()); diff --git a/src/pair.show.ts b/src/pair.show.ts index 491df6b..024dcdf 100644 --- a/src/pair.show.ts +++ b/src/pair.show.ts @@ -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)))))))); diff --git a/src/pair.ts b/src/pair.ts index 399249f..f038f6e 100644 --- a/src/pair.ts +++ b/src/pair.ts @@ -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)))); diff --git a/src/string.show.ts b/src/string.show.ts index e4468af..9a70e9b 100644 --- a/src/string.show.ts +++ b/src/string.show.ts @@ -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('"'))); diff --git a/src/string.ts b/src/string.ts index 7fa3fb0..cdd8ed4 100644 --- a/src/string.ts +++ b/src/string.ts @@ -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))))); diff --git a/test/list.spec.ts b/test/list.spec.ts index 5374bc4..8669522 100644 --- a/test/list.spec.ts +++ b/test/list.spec.ts @@ -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); }); diff --git a/test/string.spec.ts b/test/string.spec.ts index f73a2e3..2e67660 100644 --- a/test/string.spec.ts +++ b/test/string.spec.ts @@ -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'); }); });