Better debugging

master
Freywar Ulvnaudgari 2 years ago
parent df0dc199a0
commit f836e388d7
  1. 12
      src/bf.ts
  2. 4
      src/bool.show.ts
  3. 16
      src/bool.ts
  4. 4
      src/byte.show.ts
  5. 10
      src/byte.ts
  6. 4
      src/char.show.ts
  7. 4
      src/char.ts
  8. 218
      src/core.ts
  9. 48
      src/debug.ts
  10. 3
      src/index.ts
  11. 4
      src/list.show.ts
  12. 50
      src/list.ts
  13. 8
      src/log.ts
  14. 6
      src/num.show.ts
  15. 32
      src/num.ts
  16. 4
      src/ord.show.ts
  17. 14
      src/ord.ts
  18. 4
      src/pair.show.ts
  19. 4
      src/pair.ts
  20. 4
      src/string.show.ts
  21. 8
      src/string.ts
  22. 8
      test/list.spec.ts
  23. 8
      test/num.spec.ts
  24. 6
      test/string.spec.ts

@ -1,4 +1,4 @@
import { _, cnst, g, id, l, m, pipe, r } from './core'; import { _, cnst, g, id, l, n, pipe, r } from './core';
import { iif } from './bool'; import { iif } from './bool';
import { Zero, ge, ifz, pred, succ } from './num'; import { Zero, ge, ifz, pred, succ } from './num';
import { x00 } from './byte'; import { x00 } from './byte';
@ -7,7 +7,7 @@ import { Pair, first, fst, second, snd, uncurry } from './pair';
import { cons, head, repeat, set, singleton, tail, update } from './list'; import { cons, head, repeat, set, singleton, tail, update } from './list';
import { Empty, get, len, snoc } from './string'; import { Empty, get, len, snoc } from './string';
m('bf'); 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._(l('p', cnst._(uncurry._(l('is', l('cs', ge._(head._('is'))._(len._('cs')))))._('p')))));
@ -36,15 +36,15 @@ const next = g('next', second._(first._(first._(succ))));
const prev = g('prev', second._(first._(first._(pred)))); const prev = g('prev', second._(first._(first._(pred))));
const jump = g('jump', l('d', l('s', const jump = g('jump', l('d', l('s',
iif._(command._(_c('['))._('s'))._(r('bf::jump')._(succ._('d'))) iif._(command._(_c('['))._('s'))._(r('bf', 'jump')._(succ._('d')))
._(iif._(command._(_c(']'))._('s'))._(ifz._(pred._('d'))._(cnst._('s'))._(r('bf::jump')._(pred._('d')))) ._(iif._(command._(_c(']'))._('s'))._(ifz._(pred._('d'))._(cnst._('s'))._(r('bf', 'jump')._(pred._('d'))))
._(r('bf::jump')._('d')))._(advance._('s'))))); ._(r('bf', 'jump')._('d')))._(advance._('s')))));
const whlnz = g('whlnz', l('s', ifn._(read._('s'))._(jump._(Zero))._(save)._('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 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')._(r('bf', 'exec')._(advance
._(iif._(command._(_c('>'))._('s'))._(next) ._(iif._(command._(_c('>'))._('s'))._(next)
._(iif._(command._(_c('<'))._('s'))._(prev) ._(iif._(command._(_c('<'))._('s'))._(prev)
._(iif._(command._(_c('+'))._('s'))._(inc) ._(iif._(command._(_c('+'))._('s'))._(inc)

@ -1,7 +1,7 @@
import { m, g, l } from './core'; import { n, g, l } from './core';
import { iif } from './bool'; import { iif } from './bool';
import { fromString as _s } from './string'; import { fromString as _s } from './string';
m('bool.show'); n('bool.show');
export const show = g('show', l('b', iif._('b')._(_s('True'))._(_s('False')))); export const show = g('show', l('b', iif._('b')._(_s('True'))._(_s('False'))));

@ -1,7 +1,7 @@
import { $, Term, _, c, g, id, l, m, pipe } from './core'; import { $, Term, _, g, id, l, n, pipe, r } from './core';
import { EQ, GT, LT } from './ord'; import { EQ, GT, LT } from './ord';
m('bool'); n('bool');
export const True = g('True', l('t', l('_', 't'))); export const True = g('True', l('t', l('_', 't')));
@ -9,15 +9,15 @@ export const False = g('False', l('_', l('f', 'f')));
export const iif = g('iif', id); export const iif = g('iif', id);
export const not = g('not', l('b', c('b', False, True))); export const not = g('not', l('b', r('b')._(False)._(True)));
export const cmp = g('cmp', l('l', l('r', c('l', c('r', EQ, GT), c('r', LT, EQ))))); export const cmp = g('cmp', l('l', l('r', r('l')._(r('r')._(EQ)._(GT))._(r('r')._(LT)._(EQ)))));
export const lt = g('lt', l('l', c('l', False))); export const lt = g('lt', l('l', r('l')._(False)));
export const le = g('le', l('l', not._('l')._(True))); export const le = g('le', l('l', not._('l')._(True)));
export const eq = g('eq', l('l', l('r', c('l', 'r', not._('r'))))); export const eq = g('eq', l('l', l('r', r('l')._('r')._(not._('r')))));
export const ge = g('ge', l('l', pipe._(not)._(lt._('l')))); export const ge = g('ge', l('l', pipe._(not)._(lt._('l'))));
@ -25,9 +25,9 @@ export const gt = g('gt', l('l', pipe._(not)._(le._('l'))));
export const and = g('and', l('l', not._('l')._(False))); export const and = g('and', l('l', not._('l')._(False)));
export const or = g('or', l('l', c('l', True))); export const or = g('or', l('l', r('l')._(True)));
export const xor = g('xor', l('l', l('r', c('l', not._('r'), 'r')))); export const xor = g('xor', l('l', l('r', r('l')._(not._('r'))._('r'))));
export const fromBoolean: (b: boolean) => Term = b => b ? True : False; export const fromBoolean: (b: boolean) => Term = b => b ? True : False;

@ -1,5 +1,5 @@
import { m } from './core'; import { n } from './core';
m('byte.show'); n('byte.show');
export { show } from './num.show'; export { show } from './num.show';

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

@ -1,7 +1,7 @@
import { g, l, m, pipe } from './core'; import { g, l, n, pipe } from './core';
import { singleton } from './list'; import { singleton } from './list';
import { wrap, fromString as _s } from './string'; import { wrap, fromString as _s } from './string';
m('char.show'); n('char.show');
export const show = g('show', l('c', pipe._(wrap._(_s('\'')))._(singleton)._('c'))); export const show = g('show', l('c', pipe._(wrap._(_s('\'')))._(singleton)._('c')));

@ -1,8 +1,8 @@
import { Term, g, l, m, pipe } from './core'; import { Term, g, l, n, pipe } from './core';
import { toNumber as $n, fromNumber as _n, x00 } from './byte'; import { toNumber as $n, fromNumber as _n, x00 } from './byte';
import { singleton } from './list'; import { singleton } from './list';
m('char'); n('char');
export const Null = g('Null', x00); export const Null = g('Null', x00);

@ -1,4 +1,4 @@
import { withLog } from './debug'; import { withLog, withProfile } from './debug';
let index = 0; let index = 0;
@ -21,25 +21,47 @@ export abstract class Term {
} }
public context(): string { public context(): string {
return !Object.keys(this.bindings).length ? `<${this.id}>` : `<${this.id}>[bound ${Object.keys(this.bindings).join(', ')}] `; return `#${this.id}${this.cache ? '<cached>' : ''}${!Object.keys(this.bindings).length ? '' : ` [${Object.keys(this.bindings).join(', ')}]`}`;
} }
public stringify(context?: boolean): string { public expression(): string {
return `${context ? this.context() : ''}${this.constructor.name}`; return this.constructor.name;
} }
public _(arg: RefTerm): Term { public stringify(): string {
return c(this, arg); return `${this.context()} ${this.expression()}`;
} }
public _(arg: Term): Term;
public _(name: string): Term;
public _(namespace: string, name: string): Term;
public _(argOrNamespace: Term | string, maybeName?: string): Term {
return new Call(this, termify(argOrNamespace as string, maybeName as string));
}
public toString(): string {
return this.expression();
}
public toJSON(): string {
return `<${this.expression()}>`;
}
}
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 { export class Undef extends Term {
constructor( constructor() { super({}); }
public from: string,
) { super({}); }
override reduce(): Term { override reduce(): Term {
throw new Error(`${this.from} = undef`); throw new Error(`undef`);
} }
} }
@ -48,8 +70,12 @@ export class Native extends Term {
public value: any, public value: any,
) { super({}); } ) { super({}); }
public override expression(): string {
return `\`${JSON.stringify(this.value)}\``
}
public override stringify(): string { public override stringify(): string {
return `\`${JSON.stringify(this.value)}\``; return this.expression();
} }
} }
@ -70,27 +96,25 @@ export class Deferred extends Term {
} }
public override reduce(): Term { public override reduce(): Term {
const term = this.cache return this.cache = withLog(
? withLog( `Executing ${this.stringify()}`,
`Executing ${this.stringify()}`, () => withProfile(
() => this.cache!, `${this.expression()}${this.cache ? ' [cached]' : ''}`,
r => `got ${r.stringify()} (cached)`, { cat: 'deferred' },
) () => this.cache ?? Object.entries(this.bindings).reduce((t, b) => t.bind(...b), this.func(this.bindings)).reduce(),
: this.cache = withLog( ),
`Executing ${this.stringify()}`, r => `got ${r.stringify()}`,
() => this.func({ ...globals, ...this.bindings }), );
r => `got ${r.stringify()}`, }
);
return Object.entries(this.bindings).reduce((t, b) => t.bind(...b), term).reduce(); public override expression(): string {
} return '`deferred`';
public override stringify(context: boolean = true): string {
return `${context ? this.context() : ''}\`deferred\``;
} }
} }
export class Ref extends Term { export class Ref extends Term {
constructor( constructor(
public namespace: string,
public name: string, public name: string,
bindings: Record<string, Term> = {}, bindings: Record<string, Term> = {},
) { super(bindings); } ) { super(bindings); }
@ -102,27 +126,23 @@ export class Ref extends Term {
public override bind(name: string, term: Term): Term { public override bind(name: string, term: Term): Term {
return this.bindings[name] || !this.refs(name) return this.bindings[name] || !this.refs(name)
? this ? this
: new Ref(this.name, { [name]: term }); : new Ref(this.namespace, this.name, { [name]: term });
} }
public override reduce(): Term { public override reduce(): Term {
if (this.cache) { return this.cache = withLog(
return withLog( `Substituting ${this.stringify()}`,
`Substituting ${this.stringify()}`, () => withProfile(
() => this.cache!, `${this.expression()}${this.cache ? ' [cached]' : ''}`,
r => `with ${r.stringify()} (cached)`, { cat: 'ref' },
); () => this.cache ?? (this.namespace === 'local' ? this.bindings[this.name] : globals[`${this.namespace}::${this.name}`] ?? new Undef()).reduce(),
} else { ),
return this.cache = withLog( r => `with ${r.stringify()}`,
`Substituting ${this.stringify()}`, );
() => (this.bindings[this.name] ?? globals[this.name] ?? new Undef(this.name)).reduce(), }
r => `with ${r.stringify()}`,
).reduce(); override expression(): string {
} return this.name;
}
public override stringify(context = true): string {
return `${context ? this.context() : ''}${this.name}`;
} }
} }
@ -143,10 +163,10 @@ export class Lambda extends Term {
: new Lambda(this.param, this.body.bind(name, term), { ...this.bindings, [name]: term }); : new Lambda(this.param, this.body.bind(name, term), { ...this.bindings, [name]: term });
} }
public override stringify(context = true): string { public override expression(): string {
return this.body instanceof Lambda return this.body instanceof Lambda
? `${context ? this.context() : ''}\\ ${this.param} ${this.body.stringify(false).slice(2)}` ? `\\ ${this.param} ${this.body.expression().slice(2)}`
: `${context ? this.context() : ''}\\ ${this.param} . ${this.body.stringify(false)}`; : `\\ ${this.param} . ${this.body.expression()}`;
} }
} }
@ -168,69 +188,79 @@ export class Call extends Term {
} }
override reduce(): Term { override reduce(): Term {
if (this.cache) { return this.cache = withLog(
return withLog( `Reducing ${this.stringify()}`,
`Reducing ${this.stringify()}`, () => withProfile(
() => this.cache!, `${this.expression()}${this.cache ? ' [cached]' : ''}`,
r => `to ${r.stringify()} (cached)`, { cat: 'call' },
); () => this.cache ?? (() => {
} else {
return this.cache = withLog(
`Reducing ${this.stringify()}`,
() => {
const func = this.func.reduce(); const func = this.func.reduce();
if (func instanceof Lambda) { if (!(func instanceof Lambda)) {
return withLog( return new Undef();
`Applying ${func.stringify()} to ${this.arg.stringify()}`,
() => func.body.bind(func.param, this.arg),
r => `got ${r.stringify()}`,
).reduce();
} }
return this; return withLog(
}, `Binding ${this.arg.stringify()} to ${func.param}`,
r => `to ${r.stringify()}`, () => withProfile(
); `${func.param} = ${this.arg.expression()}`,
} { cat: 'binding' },
() => func.body.bind(func.param, this.arg),
),
r => `got ${r.stringify()}`,
).reduce();
})(),
),
r => `to ${r.stringify()}`,
);
} }
public override stringify(context = true): string { override expression(): string {
return `${context ? this.context() : ''}${this.func instanceof Lambda ? `(${this.func.stringify(false)})` : this.func.stringify(false)} ${this.arg instanceof Ref || this.arg instanceof Native ? this.arg.stringify(false) : `(${this.arg.stringify(false)})`}`; 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()}`;
} }
} }
const globals: Record<string, Term> = {}; const globals: Record<string, Term> = {};
type RefTerm = string | Term; let namespace: string = 'core';
const termify = (t: RefTerm) => typeof t === 'string' ? r(t) : t;
export const _ = (v: any) => new Native(v); export const n = (name: string) => namespace = name;
export const r = (name: string): Ref => new Ref(name);
export const l = (param: string, body: RefTerm): Lambda => new Lambda(param, termify(body));
export const c = (func: RefTerm, arg: RefTerm, ...args: RefTerm[]): Call =>
args.reduce<Call>((f: Call, a: RefTerm) => new Call(f, termify(a)), new Call(termify(func), termify(arg)));
export const d = (func: (bindings: Record<string, Term>) => Term) => new Deferred(func);
export const $ = <T>(t: Term): T => { export const g = (name: string, term: Term) => {
const rt = t.reduce(); const full = `${namespace}::${name}`;
return rt instanceof Native ? rt.value : rt.stringify(); if (globals[full]) {
throw new Error(`Duplicate global: "${full}"`);
}
globals[full] = term;
return new Ref(namespace, name);
}; };
let cm: string = 'core'; type Refify = {
(name: string): Ref;
(namespace: string, name: string): Ref;
}
export const m = (name: string) => cm = name; export const r: Refify = (namespaceOrName: string, name?: string) => new Ref(name ? namespaceOrName : 'local', name ?? namespaceOrName);
export const g = (name: string, term: RefTerm) => { type Lambdify = {
name = `${cm}::${name}`; (param: string, body: Term): Lambda;
if (globals[name]) { (param: string, ref: string): Lambda;
throw new Error(`Duplicate global: "${name}"`); }
}
globals[name] = termify(term); export const l: Lambdify = (param: string, body: Term | string): Lambda => new Lambda(param, termify(body as string));
return new Ref(name);
type Deferedify = {
(value: (bindings: Record<string, Term>) => Term): Deferred;
(value: boolean | number | string | object): Native;
}
export const _: Deferedify = ((value: any) => (typeof value === 'function' ? new Deferred(value) : new Native(value))) as Deferedify;
export const $ = <T>(t: Term): T => {
const rt = t.reduce();
return rt instanceof Native ? rt.value : rt.stringify();
}; };
export const undef = g('undef', new Undef('undef')); export const undef = g('undef', new Undef());
export const id = g('id', l('f', 'f')); export const id = g('id', l('f', 'f'));
export const cnst = g('cnst', l('x', l('_', 'x'))); export const cnst = g('cnst', l('x', l('_', 'x')));
export const pipe = g('pipe', l('f', l('g', l('x', c('f', c('g', 'x')))))); export const pipe = g('pipe', l('f', l('g', l('x', r('f')._(r('g')._('x'))))));

@ -1,3 +1,5 @@
import { writeFileSync } from 'node:fs';
let indent: string = ''; let indent: string = '';
const logs: string[] = []; const logs: string[] = [];
@ -6,6 +8,7 @@ export function log(): void {
logging = true; logging = true;
} }
export function withLog<T>(before: string, f: () => T, after: (v: T) => string): T { export function withLog<T>(before: string, f: () => T, after: (v: T) => string): T {
if (!logging) { if (!logging) {
return f(); return f();
@ -24,7 +27,48 @@ export function withLog<T>(before: string, f: () => T, after: (v: T) => string):
return result; return result;
} }
let profiling: boolean = false;
export function profile(): void {
profiling = true;
}
let index = 0;
export function withProfile<T>(name: string, detail: Record<'cat', string>, f: () => T) {
if (!logging) {
return f();
}
const i = index++;
performance.mark(`${name}::${i}::start`, { detail });
const result = f();
performance.mark(`${name}::${i}::end`, { detail });
performance.measure(name, {
start: `${name}::${i}::start`,
end: `${name}::${i}::end`,
detail,
});
return result;
}
export function dump() { export function dump() {
console.log('\n\nExecution log:'); if (logging) {
console.log(logs.join('\n')); console.log('\n\nExecution log:');
console.log(logs.join('\n'));
}
if (profiling) {
writeFileSync('profile.json', JSON.stringify({
pid: 0,
tid: 0,
displayTimeUnit: 'ns',
traceEvents: performance.getEntriesByType('measure').map(({ name, startTime, duration, detail }) => ({
name,
cat: (detail as { cat: string })?.cat,
ph: 'X',
ts: startTime * 1000,
dur: duration * 1000,
args: detail,
}))
}));
}
} }

@ -1,9 +1,10 @@
import { dump, log } from './debug'; import { dump, log, profile } from './debug';
import { _ } from './core'; import { _ } from './core';
import { fromNumber, toNumber } from './num'; import { fromNumber, toNumber } from './num';
import { Cons, Nil, toArray } from './list'; import { Cons, Nil, toArray } from './list';
log(); log();
profile();
const program = Cons._(fromNumber(0))._(Nil); const program = Cons._(fromNumber(0))._(Nil);

@ -1,7 +1,7 @@
import { _, g, l, m } from './core'; import { _, g, l, n } from './core';
import { concat, intersperse, map } from './list'; import { concat, intersperse, map } from './list';
import { fromString as _s, cons, snoc } from './string'; import { fromString as _s, cons, snoc } from './string';
m('list.show'); 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', l('eshow', l('xs', concat._(snoc._(cons._(_s('['))._(intersperse._(_s(', '))._(map._('eshow')._('xs'))))._(_s(']'))))));

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

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

@ -1,8 +1,8 @@
import { _, g, l, m, r } from './core'; import { _, g, l, n, r } from './core';
import { iif } from './bool'; import { iif } from './bool';
import { fromNumber as _n, sum, div, mod, lt } from './num'; import { fromNumber as _n, sum, div, mod, lt } from './num';
import { append, cons, Empty } from './string'; import { append, cons, Empty } from './string';
m('num.show'); 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._(r('num.show', 'show')._(div._('n')._(_n(10))))._(r('num.show', 'show')._(mod._('n')._(_n(10)))))));

@ -1,8 +1,8 @@
import { $, Term, _, cnst, d, g, id, l, m, pipe, r } from './core'; import { $, Term, cnst, _, g, id, l, n, pipe, r } from './core';
import { EQ, GT, LT } from './ord'; import { EQ, GT, LT } from './ord';
import { False, True, iif } from './bool'; import { False, True, iif } from './bool';
m('num'); n('num');
export const Zero = g('Zero', l('z', l('_n', 'z'))); export const Zero = g('Zero', l('z', l('_n', 'z')));
@ -14,32 +14,32 @@ export const succ = g('succ', Succ);
export const pred = g('pred', l('n', r('n')._(Zero)._(id))); export const pred = g('pred', l('n', r('n')._(Zero)._(id)));
export const cmp = g('cmp', l('l', l('r', r('l')._(r('r')._(EQ)._(cnst._(LT)))._(pipe._(r('r')._(GT))._('num::cmp'))))); export const cmp = g('cmp', l('l', l('r', r('l')._(r('r')._(EQ)._(cnst._(LT)))._(pipe._(r('r')._(GT))._('num', 'cmp')))));
export const lt = g('lt', l('l', l('r', r('r')._(False)._(r('l')._(cnst._(True))._('num::lt'))))); export const lt = g('lt', l('l', l('r', r('r')._(False)._(r('l')._(cnst._(True))._('num', 'lt')))));
export const le = g('le', l('l', l('r', r('l')._(True)._(r('r')._(cnst._(False))._('num::ge'))))); export const le = g('le', l('l', l('r', r('l')._(True)._(r('r')._(cnst._(False))._('num', 'ge')))));
export const eq = g('eq', l('l', l('r', r('l')._(r('r')._(True)._(cnst._(False)))._(r('r')._(cnst._(False))._('num::eq'))))); export const eq = g('eq', l('l', l('r', r('l')._(r('r')._(True)._(cnst._(False)))._(r('r')._(cnst._(False))._('num', 'eq')))));
export const ge = g('ge', l('l', l('r', r('r')._(True)._(r('l')._(cnst._(False))._('num::ge'))))); export const ge = g('ge', l('l', l('r', r('r')._(True)._(r('l')._(cnst._(False))._('num', 'ge')))));
export const gt = g('gt', l('l', l('r', r('l')._(False)._(r('r')._(cnst._(True))._(lt))))); export const gt = g('gt', l('l', l('r', r('l')._(False)._(r('r')._(cnst._(True))._(lt)))));
export const even = g('even', l('n', r('n')._(True)._('num::odd'))); export const even = g('even', l('n', r('n')._(True)._('num', 'odd')));
export const odd = g('odd', l('n', r('n')._(False)._('num::even'))); export const odd = g('odd', l('n', r('n')._(False)._('num', 'even')));
export const sum = g('sum', l('l', l('r', r('r')._('l')._(r('num::sum')._(Succ._('l')))))); export const sum = g('sum', l('l', l('r', r('r')._('l')._(r('num', 'sum')._(Succ._('l'))))));
export const sub = g('sub', l('l', l('r', r('r')._('l')._(r('l')._(cnst._(Zero))._('num::sub'))))); export const sub = g('sub', l('l', l('r', r('r')._('l')._(r('l')._(cnst._(Zero))._('num', 'sub')))));
export const mul = g('mul', l('l', l('r', r('l')._(Zero)._(l('pl', sum._('r')._(r('num::mul')._('pl')._('r'))))))); export const mul = g('mul', l('l', l('r', r('l')._(Zero)._(l('pl', sum._('r')._(r('num', 'mul')._('pl')._('r')))))));
export const div = g('div', l('l', l('r', iif._(lt._('l')._('r'))._(Zero)._(succ._(r('num::div')._(sub._('l')._('r'))._('r')))))); export const div = g('div', l('l', l('r', iif._(lt._('l')._('r'))._(Zero)._(succ._(r('num', 'div')._(sub._('l')._('r'))._('r'))))));
export const mod = g('mod', l('l', l('r', iif._(lt._('l')._('r'))._('l')._(r('num::mod')._(sub._('l')._('r'))._('r'))))); export const mod = g('mod', l('l', l('r', iif._(lt._('l')._('r'))._('l')._(r('num', 'mod')._(sub._('l')._('r'))._('r')))));
export const fromNumber: (n: number) => Term = n => !n ? Zero : Succ._(d(() => 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', d(bs => _(1 + toNumber(bs['p'])))))); export const toNumber: (n: Term) => number = n => $(n._(_(0))._(l('p', _(({ p }) => _(1 + toNumber(p))))));

@ -1,6 +1,6 @@
import { _, g, l, m, r } from './core'; import { _, g, l, n, r } from './core';
import { fromString as _s } from './string'; import { fromString as _s } from './string';
m('ord.show'); n('ord.show');
export const show = g('show', l('o', r('o')._(_s('LT'))._(_s('EQ'))._(_s('GT')))); export const show = g('show', l('o', r('o')._(_s('LT'))._(_s('EQ'))._(_s('GT'))));

@ -1,6 +1,6 @@
import { $, Term, _, c, g, l, m, r } from './core'; import { $, Term, _, g, l, n, r } from './core';
m('ord'); n('ord');
export const enum NOrd { export const enum NOrd {
LT, LT,
@ -14,13 +14,13 @@ export const EQ = g('EQ', l('_', l('eq', l('_', 'eq'))));
export const GT = g('GT', l('_', l('_', l('gt', 'gt')))); export const GT = g('GT', l('_', l('_', l('gt', 'gt'))));
export const eq = g('eq', l('l', l('r', c('l', export const eq = g('eq', l('l', l('r', r('l')
c('r', 'bool::True', 'bool::False', 'bool::False'), ._(r('r')._('bool', 'True')._('bool', 'False')._('bool', 'False'))
c('r', 'bool::False', 'bool::True', 'bool::False'), ._(r('r')._('bool', 'False')._('bool', 'True')._('bool', 'False'))
c('r', 'bool::False', 'bool::False', 'bool::True'))))); ._(r('r')._('bool', 'False')._('bool', 'False')._('bool', 'True')))));
export const fromNOrd: (o: NOrd) => Term export const fromNOrd: (o: NOrd) => Term
= o => o === NOrd.LT ? LT : o === NOrd.EQ ? EQ : GT; = o => o === NOrd.LT ? LT : o === NOrd.EQ ? EQ : GT;
export const toNOrd: (o: Term) => NOrd export const toNOrd: (o: Term) => NOrd
= o => $(c(o, _(NOrd.LT), _(NOrd.EQ), _(NOrd.GT)).reduce()); = o => $(o._(_(NOrd.LT))._(_(NOrd.EQ))._(_(NOrd.GT)).reduce());

@ -1,8 +1,8 @@
import { _, g, l, m, r } from './core'; import { _, g, l, n, r } from './core';
import { uncurry } from './pair'; import { uncurry } from './pair';
import { concat, cons, Nil } from './list'; import { concat, cons, Nil } from './list';
import { fromString as _s } from './string'; import { fromString as _s } from './string';
m('pair.show'); n('pair.show');
export const show = g('show', l('fshow', l('sshow', uncurry._(l('f', l('s', concat._(cons._(_s('('))._(cons._(r('fshow')._('f'))._(cons._(_s(', '))._(cons._(r('sshow')._('s'))._(cons._(_s(')'))._(Nil)))))))))))); export const show = g('show', l('fshow', l('sshow', uncurry._(l('f', l('s', concat._(cons._(_s('('))._(cons._(r('fshow')._('f'))._(cons._(_s(', '))._(cons._(r('sshow')._('s'))._(cons._(_s(')'))._(Nil))))))))))));

@ -1,9 +1,9 @@
import { _, g, l, m, r } from './core'; import { _, g, l, n, r } from './core';
import { GT, LT } from './ord'; import { GT, LT } from './ord';
import { False, True, and } from './bool'; import { False, True, and } from './bool';
import { fromString as _s } from './string'; import { fromString as _s } from './string';
m('pair'); n('pair');
export const Pair = g('Pair', l('f', l('s', l('p', r('p')._('f')._('s'))))); export const Pair = g('Pair', l('f', l('s', l('p', r('p')._('f')._('s')))));

@ -1,7 +1,7 @@
import { _, g, m } from './core'; import { _, g, n } from './core';
import { fromChar as _c } from './char'; import { fromChar as _c } from './char';
import { wrap, fromString as _s } from './string'; import { wrap, fromString as _s } from './string';
m('string.show'); n('string.show');
export const show = g('show', wrap._(_s('"'))); export const show = g('show', wrap._(_s('"')));

@ -1,10 +1,10 @@
import { $, Term, _, d, g, l, m } from './core'; import { $, Term, _, g, l, n } from './core';
import { fromChar as _c, cmp as cmpc, eq as eqc, fromChar, toChar } from './char'; import { fromChar as _c, cmp as cmpc, eq as eqc, fromChar, toChar } from './char';
import { Cons, Nil, append, cmp as cmpl, eq as eql, ge as gel, gt as gtl, le as lel, lt as ltl, nul } from './list'; import { Cons, Nil, append, cmp as cmpl, eq as eql, ge as gel, gt as gtl, le as lel, lt as ltl, nul } from './list';
export { len, Cons, cons, snoc, append, repeat, iterate, get, update, set } from './list'; export { len, Cons, cons, snoc, append, repeat, iterate, get, update, set } from './list';
m('string'); n('string');
export const Empty = g('Empty', Nil); export const Empty = g('Empty', Nil);
@ -24,6 +24,6 @@ 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', l('w', l('c', append._('w')._(append._('c')._('w')))));
export const fromString: (xs: string) => Term = s => !s.length ? Nil : Cons._(fromChar(s[0]))._(d(() => 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', d(bs => _(toChar(bs['x']) + toString(bs['xs']))))))); export const toString: (xs: Term) => string = s => $(s._(_(''))._(l('x', l('xs', _(({ x, xs }) => _(toChar(x) + toString(xs)))))));

@ -1,5 +1,5 @@
import { describe, expect, it } from '@jest/globals'; import { describe, expect, it } from '@jest/globals';
import { $, Term, _, d, g, l, m, undef } from '../src/core'; import { $, Term, _, g, l, n, undef } from '../src/core';
import { toNOrd as $o, NOrd } from '../src/ord'; import { toNOrd as $o, NOrd } from '../src/ord';
import { toBoolean as $b, iif } from '../src/bool'; 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'; 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';
@ -9,14 +9,14 @@ import { toString as $s } from '../src/string';
import { show as nshow } from '../src/num.show'; import { show as nshow } from '../src/num.show';
import { show } from '../src/list.show'; import { show } from '../src/list.show';
m('list.spec'); n('list.spec');
describe('List', () => { describe('List', () => {
const infinite: Term = g('infinite', iterate._(Succ)._(Zero)); const infinite: Term = g('infinite', iterate._(Succ)._(Zero));
const _na: (xs: number[]) => Term = xs => !xs.length ? Nil : Cons._(_n(xs[0]))._(d(() => _na(xs.slice(1)))); 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', d(bs => _([$n(bs['x']), ...$na(bs['xs'])])))))); const $na: (xs: Term) => number[] = xs => $(xs._(_([]))._(l('x', l('xs', _(({ x, xs }) => _([$n(x), ...$na(xs)]))))));
describe('toArray', () => { describe('toArray', () => {
it('converts []', () => { it('converts []', () => {

@ -1,15 +1,15 @@
import { describe, expect, it } from '@jest/globals'; import { describe, expect, it } from '@jest/globals';
import { Term, d, g, m, undef } from '../src/core'; import { Term, _, g, n, undef } from '../src/core';
import { toNOrd as $o, NOrd } from '../src/ord'; import { toNOrd as $o, NOrd } from '../src/ord';
import { toBoolean as $b, fromBoolean as _b } from '../src/bool'; 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'; 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';
import { toString as $s } from '../src/string'; import { toString as $s } from '../src/string';
import { show } from '../src/num.show'; import { show } from '../src/num.show';
m('num.spec'); n('num.spec');
describe('Num', () => { describe('Num', () => {
const infinity: Term = g('infinity', d(bs => Succ._(bs['num.spec::infinity']))); const infinity: Term = g('infinity', _(() => Succ._('num.spec', 'infinity')));
describe('toNumber', () => { describe('toNumber', () => {
it('converts 0', () => { it('converts 0', () => {

@ -1,5 +1,5 @@
import { describe, expect, it } from '@jest/globals'; import { describe, expect, it } from '@jest/globals';
import { Term, _, g, l, m, undef } from '../src/core'; import { Term, _, g, l, n, undef } from '../src/core';
import { NOrd, toNOrd } from '../src/ord'; import { NOrd, toNOrd } from '../src/ord';
import { toBoolean as $b } from '../src/bool'; import { toBoolean as $b } from '../src/bool';
import { toNumber as $n, Zero, gt as ngt } from '../src/num'; import { toNumber as $n, Zero, gt as ngt } from '../src/num';
@ -7,10 +7,10 @@ import { toChar as $c, fromChar as _c } from '../src/char';
import { toString as $s, Cons, Empty, fromString as _s, append, cmp, empty, eq, ge, gt, le, len, lt, wrap } from '../src/string'; import { toString as $s, Cons, Empty, fromString as _s, append, cmp, empty, eq, ge, gt, le, len, lt, wrap } from '../src/string';
import { show } from '../src/string.show'; import { show } from '../src/string.show';
m('string.spec'); n('string.spec');
describe('String', () => { describe('String', () => {
const infinite: Term = g('infinite', Cons._(_c('a'))._('string.spec::infinite')); const infinite: Term = g('infinite', Cons._(_c('a'))._('string.spec', 'infinite'));
describe('toString', () => { describe('toString', () => {
it('converts ""', () => { it('converts ""', () => {

Loading…
Cancel
Save