gdp-wired 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -35
- package/dist/core/compose.d.ts +38 -0
- package/dist/core/compose.js +245 -0
- package/dist/core/dsl.d.ts +85 -13
- package/dist/core/dsl.js +424 -19
- package/dist/core/machine.d.ts +34 -6
- package/dist/core/machine.js +194 -22
- package/dist/kernel/kernel.d.ts +31 -3
- package/dist/kernel/kernel.js +364 -87
- package/dist/kernel/prove.d.ts +33 -9
- package/dist/kernel/prove.js +298 -24
- package/dist/lean-kernel/emit.d.ts +132 -0
- package/dist/lean-kernel/emit.js +936 -0
- package/dist/lean-kernel/lean-terms.d.ts +5 -0
- package/dist/lean-kernel/lean-terms.js +44 -0
- package/dist/lean-kernel/library.d.ts +1 -0
- package/dist/lean-kernel/library.js +13 -0
- package/package.json +15 -4
package/dist/core/dsl.js
CHANGED
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
//
|
|
16
16
|
// A step returns its updates as one object: every right-hand side reads the state before the step, as the kernel and
|
|
17
17
|
// both runtimes do.
|
|
18
|
-
import { interpret, loadJs } from "./machine.js";
|
|
18
|
+
import { compileFunction, interpret, loadJs } from "./machine.js";
|
|
19
19
|
import { check, loopObligations } from "../kernel/kernel.js";
|
|
20
|
-
import { grow, proveLaws, proveStepLaws } from "../kernel/prove.js";
|
|
20
|
+
import { grow, proveLaws, proveLiveness, proveStepLaws } from "../kernel/prove.js";
|
|
21
21
|
// --- terms and conditions -------------------------------------------------------------------------------------------
|
|
22
22
|
const naturalConst = (v) => {
|
|
23
23
|
if (!Number.isSafeInteger(v) || v < 0)
|
|
@@ -205,6 +205,16 @@ class MaybeKind extends Kind {
|
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
207
|
export const maybe = (of) => new MaybeKind(of);
|
|
208
|
+
let boundCounter = 0;
|
|
209
|
+
// A condition at every key: only as a whole flag (`flags: ({...}) => ({covered: everyKey(k => ...)})`), the key read
|
|
210
|
+
// only as a map's key. The kernel closes it (instances where it holds, a witness where it fails).
|
|
211
|
+
export const everyKey = (f) => { const key = `k$${++boundCounter}`; return new Cond({ op: 'all', key, c: f(v(key)).c }); };
|
|
212
|
+
// Some key where f holds, in a law or a step law's conclusion (¬∀k. ¬f(k)): proven through a witness, a term naming the
|
|
213
|
+
// key, given here or found by the prover among a few candidates (kernel/prove.ts).
|
|
214
|
+
export const someKey = (f, witness) => {
|
|
215
|
+
const key = `s$${++boundCounter}`;
|
|
216
|
+
return new Cond({ op: 'not', x: { op: 'all', key, c: f(v(key)).not().c, ...(witness === undefined ? {} : { witness: termOf(witness) }) } });
|
|
217
|
+
};
|
|
208
218
|
// A map from naturals to naturals, every cell starting at `init`. One write per map per step.
|
|
209
219
|
export class MapRef {
|
|
210
220
|
name;
|
|
@@ -217,12 +227,291 @@ export class MapRef {
|
|
|
217
227
|
set(key, value) { return { map: this.name, key: termOf(key), value: termOf(value) }; }
|
|
218
228
|
// key's cell plus `by` where `c` holds (the counter every cap keeps).
|
|
219
229
|
bump(key, c = yes, by = 1) { return this.set(key, when(c, this.at(key).plus(by), this.at(key))); }
|
|
230
|
+
// Every key at once: the value at each key, the key read only as a map's key (Other.at(k)).
|
|
231
|
+
each(f) { const each = `k$${++boundCounter}`; return { map: this.name, each, value: termOf(f(v(each))) }; }
|
|
232
|
+
// As a set (cells 0 or 1): a member, and, as whole flags, every member of this one in another, none shared, the same.
|
|
233
|
+
has(key) { return this.at(key).atLeast(1); }
|
|
234
|
+
subsetOf(other) { return everyKey(k => this.at(k).atMost(other.at(k))); }
|
|
235
|
+
disjointFrom(other) { return everyKey(k => this.at(k).plus(other.at(k)).atMost(1)); }
|
|
236
|
+
sameAs(other) { return everyKey(k => this.at(k).eq(other.at(k))); }
|
|
237
|
+
// Over a universe of n names (keys 0 .. n − 1): every key past it holds 0 (a law, or a whole flag for a set a request
|
|
238
|
+
// carries), and the set's size, the sum of its cells there (exact, given `within`).
|
|
239
|
+
within(n) { naturalConst(n); return everyKey(k => k.atLeast(n).implies(this.at(k).eq(0))); }
|
|
240
|
+
sizeBelow(n) { naturalConst(n); return sum(0, ...Array.from({ length: n }, (_, key) => this.at(key))); }
|
|
241
|
+
}
|
|
242
|
+
export class ListRef {
|
|
243
|
+
name;
|
|
244
|
+
len;
|
|
245
|
+
constructor(name, len) {
|
|
246
|
+
this.name = name;
|
|
247
|
+
this.len = len;
|
|
248
|
+
}
|
|
249
|
+
at(i) { return new Term({ op: 'get', map: this.name, key: termOf(i) }); }
|
|
250
|
+
// Conditions: x at some position; each position below the next.
|
|
251
|
+
has(x) { return everyKey(k => k.lt(this.len).implies(this.at(k).ne(x))).not(); }
|
|
252
|
+
sorted() { return everyKey(k => k.plus(1).lt(this.len).implies(this.at(k).lt(this.at(k.plus(1))))); }
|
|
253
|
+
// Operations.
|
|
254
|
+
push(x, when = yes) { return { when, at: k => when_(k.eq(this.len), x, this.at(k)), len: this.len.plus(1) }; }
|
|
255
|
+
pop(when = yes) { return { when, at: k => when_(k.plus(1).eq(this.len), 0, this.at(k)), len: this.len.minus(1) }; }
|
|
256
|
+
set(i, x, when = yes) { return { when, at: k => when_(k.eq(i), x, this.at(k)), len: this.len }; }
|
|
257
|
+
insertAt(i, x, when = yes) { return { when, at: k => when_(k.lt(i), this.at(k), when_(k.eq(i), x, this.at(k.minus(1)))), len: this.len.plus(1) }; }
|
|
258
|
+
removeAt(i, when = yes) { return { when, at: k => when_(k.lt(i), this.at(k), this.at(k.plus(1))), len: this.len.minus(1) }; }
|
|
259
|
+
// The updates for the step: the first operation whose condition holds, else the list as it was.
|
|
260
|
+
apply(...ops) {
|
|
261
|
+
const each = `k$${++boundCounter}`, k = v(each);
|
|
262
|
+
const at = ops.reduceRight((acc, op) => when_(op.when, op.at(k), acc), this.at(k));
|
|
263
|
+
const len = ops.reduceRight((acc, op) => when_(op.when, op.len, acc), this.len);
|
|
264
|
+
return { [this.name]: { map: this.name, each, value: at.e }, [`${this.name}_len`]: len };
|
|
265
|
+
}
|
|
266
|
+
// Laws: nothing past the end; positions strictly increasing (so no name twice), as one law about every two keys.
|
|
267
|
+
within() { return forall(k => this.len.atMost(k).implies(this.at(k).eq(0))); }
|
|
268
|
+
increasing() { return forall((i, j) => i.lt(j).and(j.lt(this.len)).implies(this.at(i).lt(this.at(j)))); }
|
|
220
269
|
}
|
|
270
|
+
const when_ = (c, then, otherwise) => new Term({ op: 'if', c: c.c, then: termOf(then), else: termOf(otherwise) });
|
|
221
271
|
// A law about every key of a map: proven at a fresh key, assumed at the keys a step reads.
|
|
222
|
-
|
|
272
|
+
// With two parameters or more, about every two keys or more: forall((i, j) => i.lt(j).implies(...)).
|
|
273
|
+
export function forall(f) { return { forall: f }; }
|
|
274
|
+
// The keys a law's callback names: one, or two when it takes two.
|
|
275
|
+
const keysFor = (out) => [`key$${++keyCounter}`, Array.from({ length: Math.max(0, out.forall.length - 1) }, () => `key$${++keyCounter}`)];
|
|
223
276
|
// For histories: `holds` (a <= b, homogeneous over sums and queries) wherever `when` (params and plain inputs) holds.
|
|
224
277
|
export const relation = (holds, whenever = yes) => ({ when: whenever, holds });
|
|
278
|
+
// --- quantifiers anywhere ---------------------------------------------------------------------------------------------
|
|
279
|
+
// The kernel takes a condition at every key as a whole flag only (decided once per step, closed both ways). Written
|
|
280
|
+
// anywhere else in a step (inside another flag, a term's if, a write, the assumption), it is named here as a flag of its
|
|
281
|
+
// own, so every part downstream sees only whole flags. A per-step truth inside such a condition (another quantifier,
|
|
282
|
+
// or a flag) is split out by cases: ∀k. φ(k, q) is (q ∧ ∀k. φ(k, yes)) ∨ (¬q ∧ ∀k. φ(k, no)). A quantifier that reads a
|
|
283
|
+
// key bound outside it is two keys at once, which no flag is.
|
|
284
|
+
const namesIn = (t) => [...JSON.stringify(t).matchAll(/"op":"var","name":"([^"]+)"/g)].map(m => m[1]);
|
|
285
|
+
function swapC(c, from, to) {
|
|
286
|
+
if (c === from)
|
|
287
|
+
return to;
|
|
288
|
+
switch (c.op) {
|
|
289
|
+
case 'not': return { op: 'not', x: swapC(c.x, from, to) };
|
|
290
|
+
case 'and':
|
|
291
|
+
case 'or': return { op: c.op, xs: c.xs.map(y => swapC(y, from, to)) };
|
|
292
|
+
case 'all': return { op: 'all', key: c.key, c: swapC(c.c, from, to) };
|
|
293
|
+
case 'flag': return c;
|
|
294
|
+
case '<':
|
|
295
|
+
case '<=':
|
|
296
|
+
case '=': return { ...c, a: swapE(c.a, from, to), b: swapE(c.b, from, to) };
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
function swapE(e, from, to) {
|
|
300
|
+
switch (e.op) {
|
|
301
|
+
case 'var':
|
|
302
|
+
case 'const': return e;
|
|
303
|
+
case 'mul': return { ...e, a: swapE(e.a, from, to) };
|
|
304
|
+
case 'if': return { op: 'if', c: swapC(e.c, from, to), then: swapE(e.then, from, to), else: swapE(e.else, from, to) };
|
|
305
|
+
case 'get': return { ...e, key: swapE(e.key, from, to) };
|
|
306
|
+
case 'add':
|
|
307
|
+
case 'sub':
|
|
308
|
+
case 'min':
|
|
309
|
+
case 'max':
|
|
310
|
+
case 'prod': return { ...e, a: swapE(e.a, from, to), b: swapE(e.b, from, to) };
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
function perStep(c) {
|
|
314
|
+
switch (c.op) {
|
|
315
|
+
case 'flag':
|
|
316
|
+
case 'all': return c;
|
|
317
|
+
case 'not': return perStep(c.x);
|
|
318
|
+
case 'and':
|
|
319
|
+
case 'or':
|
|
320
|
+
for (const y of c.xs) {
|
|
321
|
+
const p = perStep(y);
|
|
322
|
+
if (p)
|
|
323
|
+
return p;
|
|
324
|
+
}
|
|
325
|
+
return undefined;
|
|
326
|
+
case '<':
|
|
327
|
+
case '<=':
|
|
328
|
+
case '=': return perStepE(c.a) ?? perStepE(c.b);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
function perStepE(e) {
|
|
332
|
+
switch (e.op) {
|
|
333
|
+
case 'var':
|
|
334
|
+
case 'const': return undefined;
|
|
335
|
+
case 'mul': return perStepE(e.a);
|
|
336
|
+
case 'if': return perStep(e.c) ?? perStepE(e.then) ?? perStepE(e.else);
|
|
337
|
+
case 'get': return perStepE(e.key);
|
|
338
|
+
case 'add':
|
|
339
|
+
case 'sub':
|
|
340
|
+
case 'min':
|
|
341
|
+
case 'max':
|
|
342
|
+
case 'prod': return perStepE(e.a) ?? perStepE(e.b);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
class Hoister {
|
|
346
|
+
prefix;
|
|
347
|
+
flags = {};
|
|
348
|
+
constructor(prefix) {
|
|
349
|
+
this.prefix = prefix;
|
|
350
|
+
}
|
|
351
|
+
n = 0;
|
|
352
|
+
// c with every quantifier inside it named as a flag; `bound` the keys bound outside c.
|
|
353
|
+
cond(c, bound = []) {
|
|
354
|
+
switch (c.op) {
|
|
355
|
+
case 'all': return this.quantifier(c, bound);
|
|
356
|
+
case 'flag': return c;
|
|
357
|
+
case 'not': return { op: 'not', x: this.cond(c.x, bound) };
|
|
358
|
+
case 'and':
|
|
359
|
+
case 'or': return { op: c.op, xs: c.xs.map(y => this.cond(y, bound)) };
|
|
360
|
+
case '<':
|
|
361
|
+
case '<=':
|
|
362
|
+
case '=': return { ...c, a: this.term(c.a, bound), b: this.term(c.b, bound) };
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
term(e, bound = []) {
|
|
366
|
+
switch (e.op) {
|
|
367
|
+
case 'var':
|
|
368
|
+
case 'const': return e;
|
|
369
|
+
case 'mul': return { ...e, a: this.term(e.a, bound) };
|
|
370
|
+
case 'if': return { op: 'if', c: this.cond(e.c, bound), then: this.term(e.then, bound), else: this.term(e.else, bound) };
|
|
371
|
+
case 'get': return { ...e, key: this.term(e.key, bound) };
|
|
372
|
+
case 'add':
|
|
373
|
+
case 'sub':
|
|
374
|
+
case 'min':
|
|
375
|
+
case 'max':
|
|
376
|
+
case 'prod': return { ...e, a: this.term(e.a, bound), b: this.term(e.b, bound) };
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// A quantifier as a flag (or, with per-step truths inside, a condition over flags).
|
|
380
|
+
quantifier(q, bound, name) {
|
|
381
|
+
const outer = bound.filter(key => namesIn(q).includes(key));
|
|
382
|
+
if (outer.length)
|
|
383
|
+
throw new Error(`a condition at every key reads ${outer[0]}, a key bound outside it: two keys at once are outside the kernel`);
|
|
384
|
+
const inner = perStep(q.c);
|
|
385
|
+
if (!inner) {
|
|
386
|
+
const f = name ?? `${this.prefix}${++this.n}`;
|
|
387
|
+
this.flags[f] = { op: 'all', key: q.key, c: q.c };
|
|
388
|
+
return { op: 'flag', name: f };
|
|
389
|
+
}
|
|
390
|
+
const truth = inner.op === 'flag' ? inner : this.quantifier(inner, [...bound, q.key]);
|
|
391
|
+
const split = (by) => this.quantifier({ op: 'all', key: q.key, c: swapC(q.c, inner, by) }, bound);
|
|
392
|
+
return { op: 'or', xs: [{ op: 'and', xs: [truth, split(yes.c)] }, { op: 'and', xs: [{ op: 'not', x: truth }, split(no.c)] }] };
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
// A machine built by hand (or by a combinator) with quantifiers inside its conditions, terms or writes: each named as a
|
|
396
|
+
// flag of its own, as the builders do.
|
|
397
|
+
export function nameQuantifiers(m) {
|
|
398
|
+
const hoist = new Hoister('all$'), flags = {};
|
|
399
|
+
const placed = () => { for (const [n, c] of Object.entries(hoist.flags))
|
|
400
|
+
if (!(n in flags))
|
|
401
|
+
flags[n] = c; };
|
|
402
|
+
for (const [n, c] of Object.entries(m.step.flags ?? {})) {
|
|
403
|
+
const out = c.op === 'all' ? hoist.quantifier(c, [], n) : hoist.cond(c);
|
|
404
|
+
placed();
|
|
405
|
+
if (!(n in flags))
|
|
406
|
+
flags[n] = out;
|
|
407
|
+
}
|
|
408
|
+
const state = Object.fromEntries(Object.entries(m.step.state ?? {}).map(([n, e]) => [n, hoist.term(e)]));
|
|
409
|
+
const maps = Object.fromEntries(Object.entries(m.step.maps ?? {}).map(([n, w]) => [n, 'each' in w ? { each: w.each, value: hoist.term(w.value, [w.each]) } : { key: hoist.term(w.key), value: hoist.term(w.value) }]));
|
|
410
|
+
const assume = m.assume ? hoist.cond(m.assume) : undefined;
|
|
411
|
+
placed();
|
|
412
|
+
return { ...m, step: { ...(Object.keys(flags).length ? { flags } : {}), ...(m.step.state ? { state } : {}), ...(m.step.maps ? { maps } : {}) }, ...(assume ? { assume } : {}) };
|
|
413
|
+
}
|
|
414
|
+
// A law or a step law's conclusion with quantifiers inside, each pulled out as the law's one key: ∀k. A ∧ ∀k. B is
|
|
415
|
+
// ∀k. A ∧ B, and p ∨ ∀k. A is ∀k. p ∨ A when p doesn't read the key. One under an or beside a part that reads the key
|
|
416
|
+
// is two keys at once. A quantifier under a not is some key (someKey), left for the prover's witness.
|
|
417
|
+
const hasForall = (c, positive = true) => c.op === 'all' ? positive || hasForall(c.c, positive) : c.op === 'not' ? hasForall(c.x, !positive) : c.op === 'and' || c.op === 'or' ? c.xs.some(y => hasForall(y, positive)) : false;
|
|
418
|
+
const hasAll = (c) => JSON.stringify(c).includes('"op":"all"');
|
|
419
|
+
function prenex(c, what, key) {
|
|
420
|
+
let found = false;
|
|
421
|
+
const walk = (d, positive) => {
|
|
422
|
+
switch (d.op) {
|
|
423
|
+
case 'all':
|
|
424
|
+
if (!positive)
|
|
425
|
+
return d;
|
|
426
|
+
found = true;
|
|
427
|
+
return walk(substKey(d.c, d.key, key), positive);
|
|
428
|
+
case 'not': return { op: 'not', x: walk(d.x, !positive) };
|
|
429
|
+
case 'and':
|
|
430
|
+
case 'or': {
|
|
431
|
+
if ((d.op === 'or') === positive && d.xs.some(y => hasForall(y, positive)) && d.xs.filter(y => hasForall(y, positive) || namesIn(y).includes(key)).length > 1)
|
|
432
|
+
throw new Error(`${what}: a condition at every key in an or beside another part that reads a key is two keys at once`);
|
|
433
|
+
return { op: d.op, xs: d.xs.map(y => walk(y, positive)) };
|
|
434
|
+
}
|
|
435
|
+
case 'flag': return d;
|
|
436
|
+
case '<':
|
|
437
|
+
case '<=':
|
|
438
|
+
case '=':
|
|
439
|
+
if (hasAll(d))
|
|
440
|
+
throw new Error(`${what}: a condition at every key inside a term is a flag of the rule`);
|
|
441
|
+
return d;
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
const out = walk(c, true);
|
|
445
|
+
return found ? out : undefined;
|
|
446
|
+
}
|
|
447
|
+
const substKey = (c, from, to) => JSON.parse(JSON.stringify(c).replaceAll(`"op":"var","name":"${from}"`, `"op":"var","name":"${to}"`));
|
|
448
|
+
export const fn = (arity, js, opts = {}) => {
|
|
449
|
+
if (!Number.isInteger(arity) || arity < 1)
|
|
450
|
+
throw new Error('a function takes one argument or more');
|
|
451
|
+
return { arity, js, ...opts };
|
|
452
|
+
};
|
|
453
|
+
// x / c and x mod c, rounded down, for a constant c >= 1: each with its two facts (c·q <= x < c·q + c), which Lean's omega
|
|
454
|
+
// proves of `x / c`.
|
|
455
|
+
export const divBy = (c) => {
|
|
456
|
+
if (!Number.isSafeInteger(c) || c < 1)
|
|
457
|
+
throw new RangeError('divBy takes a whole number at least 1');
|
|
458
|
+
return fn(1, `x => Math.floor(x / ${c})`, { lean: `fun x => x / ${c}`, facts: f => ({
|
|
459
|
+
[`${c}·q(x) <= x`]: forall(x => f(x).times(c).atMost(x)),
|
|
460
|
+
[`x < ${c}·q(x) + ${c}`]: forall(x => x.lt(f(x).times(c).plus(c))),
|
|
461
|
+
}) });
|
|
462
|
+
};
|
|
463
|
+
export const modBy = (c) => {
|
|
464
|
+
if (!Number.isSafeInteger(c) || c < 1)
|
|
465
|
+
throw new RangeError('modBy takes a whole number at least 1');
|
|
466
|
+
// x mod c is below c, and x less it is a multiple of c: x ∸ r = c·q for the q that divBy(c) gives; as facts about r
|
|
467
|
+
// alone, r <= x, r < c, and r(x + c) = r(x).
|
|
468
|
+
return fn(1, `x => x % ${c}`, { lean: `fun x => x % ${c}`, facts: f => ({
|
|
469
|
+
[`r(x) < ${c}`]: forall(x => f(x).lt(c)),
|
|
470
|
+
[`r(x) <= x`]: forall(x => f(x).atMost(x)),
|
|
471
|
+
[`r(x + ${c}) = r(x)`]: forall(x => f(x.plus(c)).eq(f(x))),
|
|
472
|
+
}) });
|
|
473
|
+
};
|
|
474
|
+
const pairE = (a, b) => ({ op: 'if', c: { op: '<', a, b }, then: { op: 'add', a: { op: 'prod', a: b, b }, b: a }, else: { op: 'add', a: { op: 'add', a: { op: 'prod', a, b: a }, b: a }, b } });
|
|
475
|
+
const argsKey = (args) => args.slice(1).reduce(pairE, args[0]);
|
|
476
|
+
// A function's JavaScript as one function of its key: its arguments unpaired (left-nested, as argsKey pairs them).
|
|
477
|
+
const fnSource = (name, d) => {
|
|
478
|
+
const src = typeof d.js === 'string' ? d.js : String(d.js);
|
|
479
|
+
let f;
|
|
480
|
+
try {
|
|
481
|
+
f = compileFunction([], `return (${src})`)();
|
|
482
|
+
f(...Array.from({ length: d.arity }, () => 0));
|
|
483
|
+
}
|
|
484
|
+
catch (e) {
|
|
485
|
+
throw new Error(`function ${name}: its js must be a function of its arguments that reads nothing else (${e.message})`);
|
|
486
|
+
}
|
|
487
|
+
if (d.arity === 1)
|
|
488
|
+
return src;
|
|
489
|
+
return `k => { const u = z => { const s = Math.floor(Math.sqrt(z)); return z - s * s < s ? [z - s * s, s] : [s, z - s * s - s]; }; const a = []; let z = k; for (let i = 1; i < ${d.arity}; i++) { const [p, q] = u(z); a.unshift(q); z = p; } a.unshift(z); return (${src})(...a); }`;
|
|
490
|
+
};
|
|
491
|
+
const fnTerm = (name, d) => (...args) => {
|
|
492
|
+
if (args.length !== d.arity)
|
|
493
|
+
throw new Error(`function ${name} takes ${d.arity} argument${d.arity === 1 ? '' : 's'}`);
|
|
494
|
+
return new Term({ op: 'get', map: name, key: argsKey(args.map(termOf)) });
|
|
495
|
+
};
|
|
225
496
|
let keyCounter = 0;
|
|
497
|
+
// A k-step law's later requests are built over marked names (j:name, which no rule can declare: ':' is reserved); the
|
|
498
|
+
// kernel reads them as name@j.
|
|
499
|
+
const markedName = (name) => { const m = /^(\d+):(.*)$/.exec(name); return m ? `${m[2]}@${m[1]}` : name; };
|
|
500
|
+
const markedE = (e) => {
|
|
501
|
+
switch (e.op) {
|
|
502
|
+
case 'var': return { op: 'var', name: markedName(e.name) };
|
|
503
|
+
case 'const': return e;
|
|
504
|
+
case 'mul': return { ...e, a: markedE(e.a) };
|
|
505
|
+
case 'if': return { op: 'if', c: marked(e.c), then: markedE(e.then), else: markedE(e.else) };
|
|
506
|
+
case 'get': return { op: 'get', map: e.map, key: markedE(e.key) };
|
|
507
|
+
case 'add':
|
|
508
|
+
case 'sub':
|
|
509
|
+
case 'min':
|
|
510
|
+
case 'max':
|
|
511
|
+
case 'prod': return { ...e, a: markedE(e.a), b: markedE(e.b) };
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
const marked = (c) => c.op === 'flag' ? c : c.op === 'all' ? { op: 'all', key: c.key, c: marked(c.c) } : c.op === 'not' ? { op: 'not', x: marked(c.x) } : c.op === 'and' || c.op === 'or' ? { op: c.op, xs: c.xs.map(marked) } : { ...c, a: markedE(c.a), b: markedE(c.b) };
|
|
226
515
|
// P params, I inputs, S state, M maps, F flags, R a history's record, Su its sums, Q its queries: each a record of the
|
|
227
516
|
// values the builders hand out, grown by each call.
|
|
228
517
|
export class Rule {
|
|
@@ -239,6 +528,18 @@ export class Rule {
|
|
|
239
528
|
return this.with({ state: [...this.spec.state, ...Object.entries(init)] });
|
|
240
529
|
}
|
|
241
530
|
maps(init) { return this.with({ maps: [...this.spec.maps, ...Object.entries(init)] }); }
|
|
531
|
+
// Lists, each empty at the start: a map of positions and its length <name>_len (ListRef).
|
|
532
|
+
lists(...names) {
|
|
533
|
+
return this.with({ maps: [...this.spec.maps, ...names.map(n => [n, 0])], state: [...this.spec.state, ...names.map(n => [`${n}_len`, 0])], lists: [...(this.spec.lists ?? []), ...names] });
|
|
534
|
+
}
|
|
535
|
+
// Functions defined outside the rule (fn, divBy, modBy), read like params that take arguments: f(x).
|
|
536
|
+
fns(defs) {
|
|
537
|
+
return this.with({ fns: [...(this.spec.fns ?? []), ...Object.entries(defs)] });
|
|
538
|
+
}
|
|
539
|
+
// What is given about the functions (with their own facts): laws over the params and functions, each by name.
|
|
540
|
+
facts(f) { return this.with({ facts: [...(this.spec.facts ?? []), f] }); }
|
|
541
|
+
// Maps each request carries whole (a set of names, say: cells 0 or 1), every cell past them 0; read like any map.
|
|
542
|
+
carries(...names) { return this.with({ carried: [...(this.spec.carried ?? []), ...names] }); }
|
|
242
543
|
// Named conditions of the step, decided once per step before it; each call's flags may read the earlier calls'. A flag
|
|
243
544
|
// named again replaces the earlier definition in place (what a variant needs: one call, the step unchanged); the new
|
|
244
545
|
// definition may read only the flags defined before the original's place, as the kernel checks.
|
|
@@ -270,12 +571,15 @@ export class Rule {
|
|
|
270
571
|
// (the kernel proves it adds nothing to any query).
|
|
271
572
|
prune(order, after) { return this.with({ prune: { order, after: after } }); }
|
|
272
573
|
// A law about the params, the state, the maps and the sums (not a request): `forall` for every key of a map.
|
|
273
|
-
law(name, f) {
|
|
274
|
-
|
|
275
|
-
if (out instanceof Cond)
|
|
276
|
-
return { name, holds: out.c };
|
|
574
|
+
law(name, f) { return this.lawOf(name, f(this.env({ flags: false, inputs: false, queries: false }))); }
|
|
575
|
+
lawOf(name, out) {
|
|
277
576
|
const key = `key$${++keyCounter}`;
|
|
278
|
-
|
|
577
|
+
if (out instanceof Cond) {
|
|
578
|
+
const p = prenex(out.c, `law ${name}`, key);
|
|
579
|
+
return p ? { name, forall: key, holds: p } : { name, holds: out.c };
|
|
580
|
+
}
|
|
581
|
+
const [k1, more] = keysFor(out), holds = out.forall(v(k1), ...more.map(v)).c;
|
|
582
|
+
return more.length ? { name, forall: k1, keys: more, holds } : { name, forall: k1, holds: prenex(holds, `law ${name}`, k1) ?? holds };
|
|
279
583
|
}
|
|
280
584
|
// A law about one step, for every request the rule allows: `then(before, after)` relates what the step reads (params,
|
|
281
585
|
// the request, state, maps, flags, sums, queries) to the state, maps and sums after it. `when` narrows the requests.
|
|
@@ -289,11 +593,67 @@ export class Rule {
|
|
|
289
593
|
after[n] = v(`${n}'`);
|
|
290
594
|
for (const [n, init] of this.spec.maps)
|
|
291
595
|
after[n] = new MapRef(`${n}'`, init);
|
|
596
|
+
for (const n of this.spec.lists ?? [])
|
|
597
|
+
after[n] = new ListRef(`${n}'`, v(`${n}_len'`));
|
|
292
598
|
const out = then(env, after), w = when ? { when: when(env).c } : {};
|
|
293
|
-
if (out instanceof Cond)
|
|
294
|
-
return { name, then: out.c, ...w };
|
|
295
599
|
const key = `key$${++keyCounter}`;
|
|
296
|
-
|
|
600
|
+
if (out instanceof Cond) {
|
|
601
|
+
const p = prenex(out.c, `step law ${name}`, key);
|
|
602
|
+
return p ? { name, forall: key, then: p, ...w } : { name, then: out.c, ...w };
|
|
603
|
+
}
|
|
604
|
+
const [k1, more] = keysFor(out), c = out.forall(v(k1), ...more.map(v)).c;
|
|
605
|
+
return more.length ? { name, forall: k1, keys: more, then: c, ...w } : { name, forall: k1, then: prenex(c, `step law ${name}`, k1) ?? c, ...w };
|
|
606
|
+
}
|
|
607
|
+
// A law about k steps in a row (k from 2 to 16): `then(first, last, requests)` relates what the first step reads to the
|
|
608
|
+
// state, maps and sums after the last, with each step's request and queries (requests[0] is the first's); `when(before,
|
|
609
|
+
// j)` narrows the j-th step's request (j from 0), read at the state that step starts from.
|
|
610
|
+
// meter.stepsLaw('two requests spend at most 2m', 2, ({spent, m}, after) => after.spent.atMost(spent.plus(m).plus(m)))
|
|
611
|
+
stepsLaw(name, k, then, when) {
|
|
612
|
+
const env = this.env();
|
|
613
|
+
const after = {};
|
|
614
|
+
for (const [n] of this.spec.state)
|
|
615
|
+
after[n] = v(`${n}'`);
|
|
616
|
+
for (const [n] of this.spec.sums)
|
|
617
|
+
after[n] = v(`${n}'`);
|
|
618
|
+
for (const [n, init] of this.spec.maps)
|
|
619
|
+
after[n] = new MapRef(`${n}'`, init);
|
|
620
|
+
for (const n of this.spec.lists ?? [])
|
|
621
|
+
after[n] = new ListRef(`${n}'`, v(`${n}_len'`));
|
|
622
|
+
// The j-th request's values over marked names, renamed to the kernel's input@j once built.
|
|
623
|
+
const mark = (j) => `${j}:`;
|
|
624
|
+
const requests = Array.from({ length: k }, (_, j) => {
|
|
625
|
+
if (j === 0)
|
|
626
|
+
return Object.fromEntries([...this.spec.inputs.map(([n]) => n), ...this.spec.queries.map(([n]) => n)].map(n => [n, env[n]]));
|
|
627
|
+
return Object.fromEntries([...this.spec.inputs.map(([n, kind]) => [n, kind.value(n, mark(j + 1))]), ...this.spec.queries.map(([n]) => [n, v(`${mark(j + 1)}${n}`)])]);
|
|
628
|
+
});
|
|
629
|
+
const out = then(env, after, requests);
|
|
630
|
+
const whens = when ? Array.from({ length: k }, (_, j) => when(env, j)) : [];
|
|
631
|
+
while (whens.length && whens.at(-1) === undefined)
|
|
632
|
+
whens.pop();
|
|
633
|
+
const w = whens.length ? { when: whens.map(c => (c ?? lit(0).atMost(0)).c) } : {};
|
|
634
|
+
const key = `key$${++keyCounter}`;
|
|
635
|
+
if (out instanceof Cond) {
|
|
636
|
+
const p = prenex(out.c, `step law ${name}`, key);
|
|
637
|
+
return p ? { name, steps: k, forall: key, then: marked(p), ...w } : { name, steps: k, then: marked(out.c), ...w };
|
|
638
|
+
}
|
|
639
|
+
const [k1, more] = keysFor(out), c = out.forall(v(k1), ...more.map(v)).c;
|
|
640
|
+
return more.length ? { name, steps: k, forall: k1, keys: more, then: marked(c), ...w } : { name, steps: k, forall: k1, then: marked(prenex(c, `step law ${name}`, k1) ?? c), ...w };
|
|
641
|
+
}
|
|
642
|
+
// "Whenever `from` holds, `to` holds later", in every run that takes each helpful request infinitely often: proven by
|
|
643
|
+
// a rank (a natural over the state and params, or several compared in order) that no step raises while `from` holds
|
|
644
|
+
// and `to` doesn't, except by reaching `to`, and that each helpful request lowers (or it reaches `to`). A helpful
|
|
645
|
+
// request names some inputs by terms over the state and params, the rest left free; with several, each comes with the
|
|
646
|
+
// region where it helps (`when`), some region always holds, and a step that keeps the rank keeps its region.
|
|
647
|
+
// queue.leadsTo('every ticket is served', {from: ({t, next, served}) => t.lt(next).and(served.atMost(t)), to: ({t, served}) => served.gt(t),
|
|
648
|
+
// rank: ({t, served}) => t.plus(1).minus(served), helpful: () => ({op: 1})})
|
|
649
|
+
// batches.leadsTo('every batch is done', {from: () => yes, to: ({waiting, items}) => waiting.eq(0).and(items.eq(0)),
|
|
650
|
+
// rank: ({waiting, items}) => [waiting, items], helpful: [{when: ({items}) => items.gt(0), request: () => ({op: 1})}, {when: ({items}) => items.eq(0), request: () => ({op: 0})}]})
|
|
651
|
+
leadsTo(name, spec) {
|
|
652
|
+
const env = this.env({ flags: false, inputs: false, queries: false });
|
|
653
|
+
const req = (f) => Object.fromEntries(Object.entries(f(env)).map(([n, t]) => [n, termOf(t)]));
|
|
654
|
+
const r = spec.rank(env), rank = Array.isArray(r) ? r.map(termOf) : termOf(r);
|
|
655
|
+
const base = { name, from: spec.from(env).c, to: spec.to(env).c, rank };
|
|
656
|
+
return typeof spec.helpful === 'function' ? { ...base, request: req(spec.helpful) } : { ...base, helpful: spec.helpful.map(h => ({ ...(h.when ? { when: h.when(env).c } : {}), request: req(h.request) })) };
|
|
297
657
|
}
|
|
298
658
|
// A decision: whenever the params and the request meet `given`, `then` holds. Decisions don't read the state.
|
|
299
659
|
decide(name, given, then) {
|
|
@@ -313,14 +673,21 @@ export class Rule {
|
|
|
313
673
|
const out = {};
|
|
314
674
|
for (const [n, k] of this.spec.params)
|
|
315
675
|
out[n] = k.value(n);
|
|
316
|
-
|
|
676
|
+
for (const [n, d] of this.spec.fns ?? [])
|
|
677
|
+
out[n] = fnTerm(n, d);
|
|
678
|
+
if (parts.inputs !== false) {
|
|
317
679
|
for (const [n, k] of this.spec.inputs)
|
|
318
680
|
out[n] = k.value(n);
|
|
681
|
+
for (const n of this.spec.carried ?? [])
|
|
682
|
+
out[n] = new MapRef(n, 0);
|
|
683
|
+
}
|
|
319
684
|
if (parts.state !== false) {
|
|
320
685
|
for (const [n] of this.spec.state)
|
|
321
686
|
out[n] = v(n);
|
|
322
687
|
for (const [n, init] of this.spec.maps)
|
|
323
688
|
out[n] = new MapRef(n, init);
|
|
689
|
+
for (const n of this.spec.lists ?? [])
|
|
690
|
+
out[n] = new ListRef(n, v(`${n}_len`));
|
|
324
691
|
for (const [n] of this.spec.sums)
|
|
325
692
|
out[n] = v(n);
|
|
326
693
|
}
|
|
@@ -339,12 +706,23 @@ export class Rule {
|
|
|
339
706
|
const inputs = [...s.inputs.flatMap(([n, k]) => k.vars(n)), ...queries];
|
|
340
707
|
const pEnv = this.env({ inputs: false, state: false, flags: false, queries: false });
|
|
341
708
|
const env = this.env({ flags: false });
|
|
342
|
-
const
|
|
709
|
+
const declared = {};
|
|
343
710
|
for (const f of s.flags)
|
|
344
711
|
for (const [n, c] of Object.entries(f(env))) {
|
|
345
|
-
|
|
712
|
+
declared[n] = c.c;
|
|
346
713
|
env[n] = new Cond({ op: 'flag', name: n });
|
|
347
714
|
} // a name again: replaced in place
|
|
715
|
+
// Quantifiers anywhere, named as flags: each placed before the flag that reads it.
|
|
716
|
+
const hoist = new Hoister('all$'), flags = {};
|
|
717
|
+
const placed = () => { for (const [n, c] of Object.entries(hoist.flags))
|
|
718
|
+
if (!(n in flags))
|
|
719
|
+
flags[n] = c; };
|
|
720
|
+
for (const [n, c] of Object.entries(declared)) {
|
|
721
|
+
const out = c.op === 'all' ? hoist.quantifier(c, [], n) : hoist.cond(c);
|
|
722
|
+
placed();
|
|
723
|
+
if (!(n in flags))
|
|
724
|
+
flags[n] = out;
|
|
725
|
+
}
|
|
348
726
|
const updates = s.step?.(env) ?? {};
|
|
349
727
|
const state = {}, maps = {};
|
|
350
728
|
for (const [n, u] of Object.entries(updates)) {
|
|
@@ -353,20 +731,30 @@ export class Rule {
|
|
|
353
731
|
if (typeof u === 'object' && 'map' in u) {
|
|
354
732
|
if (u.map !== n)
|
|
355
733
|
throw new Error(`${s.name}: the step writes map ${u.map} under the name ${n}`);
|
|
356
|
-
maps[n] = { key: u.key, value: u.value };
|
|
734
|
+
maps[n] = 'each' in u ? { each: u.each, value: hoist.term(u.value, [u.each]) } : { key: hoist.term(u.key), value: hoist.term(u.value) };
|
|
357
735
|
}
|
|
358
736
|
else
|
|
359
|
-
state[n] = termOf(u);
|
|
737
|
+
state[n] = hoist.term(termOf(u));
|
|
360
738
|
}
|
|
361
739
|
const pre = [...this.kindAssumptions('params'), ...s.pre.map(f => f(pEnv).c)];
|
|
362
|
-
const assume = [...this.kindAssumptions('inputs'), ...s.assume.map(f => f(env).c)];
|
|
740
|
+
const assume = [...this.kindAssumptions('inputs'), ...s.assume.map(f => hoist.cond(f(env).c))];
|
|
741
|
+
placed();
|
|
742
|
+
// Functions, and their facts: each function's own (named after it), then the rule's.
|
|
743
|
+
const fns = Object.fromEntries((s.fns ?? []).map(([n, d]) => [n, { js: fnSource(n, d), ...(d.lean ? { lean: d.lean } : {}) }]));
|
|
744
|
+
const facts = [
|
|
745
|
+
...(s.fns ?? []).flatMap(([n, d]) => Object.entries(d.facts?.(fnTerm(n, d)) ?? {}).map(([name, f]) => this.lawOf(`${n}: ${name}`, f))),
|
|
746
|
+
...(s.facts ?? []).flatMap(f => Object.entries(f(pEnv)).map(([name, out]) => this.lawOf(name, out))),
|
|
747
|
+
];
|
|
363
748
|
const m = {
|
|
364
749
|
name: s.name, params, inputs,
|
|
365
750
|
state: Object.fromEntries(s.state.map(([n, init]) => [n, typeof init === 'number' ? termOf(init) : termOf(init(pEnv))])),
|
|
366
751
|
...(s.maps.length ? { maps: Object.fromEntries(s.maps) } : {}),
|
|
752
|
+
...(s.carried?.length ? { inputMaps: s.carried } : {}),
|
|
367
753
|
step: { ...(Object.keys(flags).length ? { flags } : {}), ...(Object.keys(state).length ? { state } : {}), ...(Object.keys(maps).length ? { maps } : {}) },
|
|
368
754
|
...(pre.length ? { pre: pre.length === 1 ? pre[0] : { op: 'and', xs: pre } } : {}),
|
|
369
755
|
...(assume.length ? { assume: assume.length === 1 ? assume[0] : { op: 'and', xs: assume } } : {}),
|
|
756
|
+
...(Object.keys(fns).length ? { fns } : {}),
|
|
757
|
+
...(facts.length ? { facts } : {}),
|
|
370
758
|
};
|
|
371
759
|
if (s.record) {
|
|
372
760
|
const kinds = new Map(s.inputs);
|
|
@@ -390,10 +778,23 @@ export class Rule {
|
|
|
390
778
|
// --- running it -----------------------------------------------------------------------------------------------------
|
|
391
779
|
// Runtime values (numbers, booleans, choice names, null for a missing value) to the variables the machine reads.
|
|
392
780
|
encodeParams(values) { return encode(this.spec.params, values); }
|
|
393
|
-
|
|
781
|
+
// A carried map is a Set of keys (each cell 1), an array of them, or a Map of key to natural.
|
|
782
|
+
encodeInput(values) {
|
|
783
|
+
const out = encode(this.spec.inputs, values);
|
|
784
|
+
for (const n of this.spec.carried ?? []) {
|
|
785
|
+
const given = values[n];
|
|
786
|
+
out[n] = given instanceof Map ? new Map(given) : new Map([...given].map(key => [key, 1]));
|
|
787
|
+
}
|
|
788
|
+
return out;
|
|
789
|
+
}
|
|
394
790
|
// Random params and inputs that meet their kinds (not the user's `pre` or `assume`, which a caller checks).
|
|
395
791
|
randomParams(rand, bound) { return Object.assign({}, ...this.spec.params.map(([n, k]) => k.random(n, rand, bound))); }
|
|
396
|
-
randomInput(rand, bound) {
|
|
792
|
+
randomInput(rand, bound) {
|
|
793
|
+
const out = Object.assign({}, ...this.spec.inputs.map(([n, k]) => k.random(n, rand, bound)));
|
|
794
|
+
for (const n of this.spec.carried ?? [])
|
|
795
|
+
out[n] = new Map(Array.from({ length: bound + 1 }, (_, key) => [key, rand(2)]).filter(([, cell]) => cell === 1));
|
|
796
|
+
return out;
|
|
797
|
+
}
|
|
397
798
|
// The prune order's variable, if the history is pruned (a runtime must send it nondecreasing).
|
|
398
799
|
get orderedBy() { return this.spec.prune ? new Map(this.spec.inputs).get(this.spec.prune.order).vars(this.spec.prune.order)[0] : undefined; }
|
|
399
800
|
interpreter() { return interpret(this.machine); }
|
|
@@ -474,5 +875,9 @@ export function proveSteps(r, laws, stepLaws) {
|
|
|
474
875
|
const out = proveStepLaws(r.machine, laws, stepLaws);
|
|
475
876
|
return { proven: out.proven, checked: out.checked, ...(out.failed ? { goal: out.failed.goal, stuck: out.failed.stuck, ...(out.failed.witness ? { witness: out.failed.witness } : {}) } : {}) };
|
|
476
877
|
}
|
|
878
|
+
export function proveLeadsTo(r, laws, l) {
|
|
879
|
+
const out = proveLiveness(r.machine, laws, l);
|
|
880
|
+
return { proven: out.proven, checked: out.checked, ...(out.failed ? { goal: out.failed.goal, stuck: out.failed.stuck, ...(out.failed.witness ? { witness: out.failed.witness } : {}) } : {}) };
|
|
881
|
+
}
|
|
477
882
|
export const proveDecision = (d) => goalsVerdict([d.goal]);
|
|
478
883
|
export const proveLoop = (l, laws) => goalsVerdict(loopObligations(l.loop, laws, l.rankTerms));
|
package/dist/core/machine.d.ts
CHANGED
|
@@ -43,6 +43,11 @@ export type C = {
|
|
|
43
43
|
} | {
|
|
44
44
|
op: 'flag';
|
|
45
45
|
name: string;
|
|
46
|
+
} | {
|
|
47
|
+
op: 'all';
|
|
48
|
+
key: string;
|
|
49
|
+
c: C;
|
|
50
|
+
witness?: E;
|
|
46
51
|
};
|
|
47
52
|
export type Machine = {
|
|
48
53
|
name: string;
|
|
@@ -50,17 +55,21 @@ export type Machine = {
|
|
|
50
55
|
inputs: string[];
|
|
51
56
|
state: Record<string, E>;
|
|
52
57
|
maps?: Record<string, number>;
|
|
58
|
+
inputMaps?: string[];
|
|
53
59
|
step: {
|
|
54
60
|
flags?: Record<string, C>;
|
|
55
61
|
state?: Record<string, E>;
|
|
56
|
-
maps?: Record<string,
|
|
57
|
-
key: E;
|
|
58
|
-
value: E;
|
|
59
|
-
}>;
|
|
62
|
+
maps?: Record<string, MapUpdate>;
|
|
60
63
|
};
|
|
61
64
|
pre?: C;
|
|
62
65
|
assume?: C;
|
|
63
66
|
history?: History;
|
|
67
|
+
fns?: Record<string, Fn>;
|
|
68
|
+
facts?: Law[];
|
|
69
|
+
};
|
|
70
|
+
export type Fn = {
|
|
71
|
+
js: string;
|
|
72
|
+
lean?: string;
|
|
64
73
|
};
|
|
65
74
|
export type History = {
|
|
66
75
|
keep: C;
|
|
@@ -76,10 +85,24 @@ export type History = {
|
|
|
76
85
|
after: E;
|
|
77
86
|
};
|
|
78
87
|
};
|
|
88
|
+
export type MapUpdate = {
|
|
89
|
+
key: E;
|
|
90
|
+
value: E;
|
|
91
|
+
} | {
|
|
92
|
+
each: string;
|
|
93
|
+
value: E;
|
|
94
|
+
};
|
|
95
|
+
export declare const pointWrite: (w: MapUpdate, where: string) => {
|
|
96
|
+
key: E;
|
|
97
|
+
value: E;
|
|
98
|
+
};
|
|
99
|
+
export declare const noQuantifier: (where: string) => never;
|
|
79
100
|
export type Law = {
|
|
80
101
|
name: string;
|
|
81
102
|
holds: C;
|
|
82
103
|
forall?: string;
|
|
104
|
+
keys?: string[];
|
|
105
|
+
stated?: C;
|
|
83
106
|
};
|
|
84
107
|
export { unreachable } from '../kernel/kernel.js';
|
|
85
108
|
export declare const x: (name: string) => E;
|
|
@@ -102,17 +125,22 @@ export declare const bit: (name: string) => C;
|
|
|
102
125
|
export type State = {
|
|
103
126
|
scalars: Record<string, number>;
|
|
104
127
|
maps: Record<string, Map<number, number>>;
|
|
128
|
+
defaults?: Record<string, number>;
|
|
105
129
|
history?: Env[];
|
|
106
130
|
last?: number;
|
|
107
131
|
};
|
|
108
132
|
type Env = Record<string, number>;
|
|
133
|
+
export type Request = Record<string, number | ReadonlyMap<number, number>>;
|
|
109
134
|
export declare const naturalIn: (v: unknown, what: string) => number;
|
|
110
135
|
export declare function evalE(e: E, env: Env, st: State, m: Machine): number;
|
|
136
|
+
export declare const fnValue: (fn: Fn, key: number) => number;
|
|
111
137
|
export declare function evalC(c: C, env: Env, st: State, m: Machine): boolean;
|
|
138
|
+
export declare function carriedView(m: Machine, st: State, input: Request, rename?: (map: string) => string): State;
|
|
139
|
+
export declare const numbersOf: (input: Request) => Record<string, number>;
|
|
112
140
|
export declare function interpret(m: Machine): {
|
|
113
141
|
init: (params: Env) => State;
|
|
114
|
-
queries: (params: Env, st: State, input:
|
|
115
|
-
step: (params: Env,
|
|
142
|
+
queries: (params: Env, st: State, input: Request) => Env;
|
|
143
|
+
step: (params: Env, given: State, input: Request) => State;
|
|
116
144
|
};
|
|
117
145
|
export declare function compileJs(m: Machine): string;
|
|
118
146
|
export declare function compileFunction<F>(params: string[], body: string): F;
|