gdp-wired 0.7.0 → 0.9.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 +51 -6
- package/dist/core/dsl.d.ts +164 -13
- package/dist/core/dsl.js +525 -27
- package/dist/core/gdp.d.ts +4 -8
- package/dist/core/gdp.js +4 -11
- package/dist/core/machine.d.ts +28 -0
- package/dist/kernel/prove.js +39 -2
- package/dist/lean-kernel/emit.d.ts +9 -1
- package/dist/lean-kernel/emit.js +264 -20
- package/dist/lean-kernel/lean-terms.d.ts +4 -0
- package/dist/lean-kernel/lean-terms.js +38 -0
- package/dist/lean-kernel/library.js +5 -5
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -61,6 +61,12 @@ All of these are proven automatically, and each proof is also a Lean theorem:
|
|
|
61
61
|
- **Refinement**: an implementation behaves like a simpler spec, step for step (`examples/composition.ts`).
|
|
62
62
|
- **Functions**: division, remainder, and your own functions, known by their facts; a function defined in Lean brings
|
|
63
63
|
facts proven there (`examples/functions.ts`).
|
|
64
|
+
- **Lemmas you state**: a function defined by a recurrence (`recur`), of one argument or several, reading other
|
|
65
|
+
functions, and lemmas about it proven by induction, at one point or between two, which every rule that reads it may
|
|
66
|
+
then use: a backoff delay is at most 64 at every attempt and never shrinks (`examples/lemmas.ts`).
|
|
67
|
+
- **Records and variants**: inputs, state, results, map cells and list items made of named fields, or one of several
|
|
68
|
+
cases each with fields of its own (a payment by card or in cash, a seat free, held or sold), every case covered
|
|
69
|
+
(`examples/datatypes.ts`).
|
|
64
70
|
- **Pure functions and two-run laws**: laws about what a function returns, and laws comparing two calls, like "the
|
|
65
71
|
secret never changes the answer". `examples/jev-fabric/` ports a Bend project's policy core and proves all 59 laws its
|
|
66
72
|
Bend proofs state.
|
|
@@ -71,7 +77,7 @@ synthesizer finds one and the kernel proves it.
|
|
|
71
77
|
**What it leaves to Lean or Bend.** Two things, and neither is a gap the next feature closes: proofs the prover would
|
|
72
78
|
have to invent (induction over a recursive structure whose proof needs a lemma nobody stated, and arithmetic with
|
|
73
79
|
products of unknowns beyond multiplying two known facts; integer arithmetic with induction or with products is
|
|
74
|
-
undecidable), and shipping an arbitrary algorithm as its proved source (gdp-wired ships the rule as JavaScript; Bend
|
|
80
|
+
undecidable; a lemma you state about a recurrence is proven, but a recursive datatype as a value is Lean's), and shipping an arbitrary algorithm as its proved source (gdp-wired ships the rule as JavaScript; Bend
|
|
75
81
|
compiles the proved source itself). The full list of what is and isn't in scope is in
|
|
76
82
|
[`docs/comparison.md`](docs/comparison.md#gdp-wireds-scope-in-detail).
|
|
77
83
|
|
|
@@ -145,7 +151,7 @@ The builders (`core/dsl.ts`) hand out typed values for every name you declare; e
|
|
|
145
151
|
the kernel checks, so nothing in them is trusted.
|
|
146
152
|
|
|
147
153
|
```ts
|
|
148
|
-
import {bool, count, forall, maybe, nat, oneOf, proveSteps, relation, rule, yes} from 'gdp-wired'
|
|
154
|
+
import {bool, count, forall, fun, maybe, min, nat, no, oneOf, proveSteps, record, recur, relation, rule, variant, when, yes} from 'gdp-wired'
|
|
149
155
|
|
|
150
156
|
// Maps and flags: a grant is decided once per step; each map is written once; a map law holds at every key.
|
|
151
157
|
const caps = rule('caps')
|
|
@@ -180,12 +186,39 @@ const window = rule('window limit')
|
|
|
180
186
|
const trial = rule('trial').inputs({plan: oneOf('free', 'pro'), spent: maybe(nat), allowance: maybe(nat)})
|
|
181
187
|
const failsClosed = trial.decide('a missing fact means no trial', ({spent}) => spent.isNone,
|
|
182
188
|
({plan, spent, allowance}) => plan.match({free: () => spent.match({none: () => yes, some: s => allowance.match({none: () => yes, some: a => s.atLeast(a)})}), pro: () => yes}))
|
|
189
|
+
|
|
190
|
+
// Records and variants: a payment is by card or in cash, each with fields of its own, read only in `match`.
|
|
191
|
+
const Pay = variant({card: {amount: nat, verified: bool}, cash: {amount: nat}})
|
|
192
|
+
const approve = fun('approve').inputs({pay: Pay, who: record({limit: nat, blocked: bool})})
|
|
193
|
+
.returns(({pay, who}) => ({ok: who.blocked.not().and(pay.match({card: c => c.verified.and(c.amount.atMost(who.limit)), cash: c => c.amount.atMost(200)}))}))
|
|
194
|
+
const unverified = approve.law('an unverified card is never approved', ({pay}, out) => [pay.match({card: c => c.verified.not(), cash: () => no}), out.ok], () => no)
|
|
195
|
+
|
|
196
|
+
// A lemma you state, proven by induction: the backoff delay is defined by its recurrence, and its lemmas are facts
|
|
197
|
+
// every rule that reads it may use (its two equations alone don't bound it at an unknown attempt).
|
|
198
|
+
const delay = recur('delay', {zero: 1, next: (_, d) => min(d.times(2), 64)}, {'at least 1': (_, d) => d.atLeast(1), 'at most 64': (_, d) => d.atMost(64)})
|
|
199
|
+
const retry = rule('retry').inputs({failed: bool, now: nat}).state({tries: 0, next: 0, last: 0}).fns({delay})
|
|
200
|
+
.assume(({now, last}) => now.atLeast(last))
|
|
201
|
+
.step(({failed, now, tries, next, delay}) => ({tries: when(failed, tries.plus(1), 0), next: when(failed.and(now.atLeast(next)), now.plus(delay(tries)), next), last: now}))
|
|
202
|
+
const soon = retry.law('the next try is at most 64 after the last request', ({next, last}) => next.atMost(last.plus(64)))
|
|
183
203
|
```
|
|
184
204
|
|
|
185
205
|
|
|
186
|
-
- **Kinds**: `nat`, `upTo(k)`, `bool`, `oneOf(...)`, `maybe(kind)`, `int`, `decimal(places)`, `str({like, maxLength})
|
|
187
|
-
their assumptions (a bit is 0 or 1, a choice is in range) go to the kernel by
|
|
188
|
-
`encodeInput`/`encodeParams` turn runtime values into the numbers the machine reads.
|
|
206
|
+
- **Kinds**: `nat`, `upTo(k)`, `bool`, `oneOf(...)`, `maybe(kind)`, `int`, `decimal(places)`, `str({like, maxLength})`,
|
|
207
|
+
`record({...})`, `variant({...})`; their assumptions (a bit is 0 or 1, a choice is in range) go to the kernel by
|
|
208
|
+
themselves, and `encodeInput`/`encodeParams` turn runtime values into the numbers the machine reads.
|
|
209
|
+
- **Records and variants**: `record({limit: nat, blocked: bool})` hands out an object of its fields' values;
|
|
210
|
+
`variant({card: {...}, cash: {...}})` a value with `is(case)` and `match({card: c => ..., cash: c => ...})`, the only
|
|
211
|
+
place a case's fields are read. `Pay.make({tag: 'card', amount, verified})` builds a case to write or to pass to
|
|
212
|
+
`when`, and `same(a, b)` compares two values of one kind part by part; `optional(c, value)` is a value present where c
|
|
213
|
+
holds (a result that may be missing). At runtime a record is an object of its fields and a variant `{tag: 'card',
|
|
214
|
+
...fields}` (or the key given, `variant({...}, {tag: 'kind'})`); a field or case the kind doesn't declare is refused.
|
|
215
|
+
What a kind keeps true of the values a step writes (a case in range, a flag 0 or 1) is a law of its own, `r.kindLaws()`,
|
|
216
|
+
which proveRule, proveSteps and proveLeadsTo prove beside the laws they are given. Both are their fields'
|
|
217
|
+
variables underneath (`pay.card.amount`, and the case's index as `pay`), so the kernel, both runtimes and the Lean
|
|
218
|
+
twin see nothing new. Maps and lists of them: `.maps({Acct: record({...}).from({...})})` (`Acct.at(k)`,
|
|
219
|
+
`Acct.set(k, value)`, `Acct.each(k => value)`) and `.items({Queue: Job})` (`push`, `pop`, `set`, `insertAt`,
|
|
220
|
+
`removeAt`, `apply`, `has`, `within`, `increasing(by)`), one map per variable of the kind; `rule.decode` reads them back
|
|
221
|
+
as objects and arrays. Not as values: recursive types (a tree).
|
|
189
222
|
- **State of any kind**: `.state({open: bool.from(true), status: oneOf('new', 'done').from('new'), owner: str().from(''), note: maybe(nat).from(null)})`;
|
|
190
223
|
a step writes each kind's own values, `when(c, a, b)` chooses between any two values of a kind, and `rule.decode(state)`
|
|
191
224
|
reads them back as runtime values.
|
|
@@ -206,6 +239,18 @@ const failsClosed = trial.decide('a missing fact means no trial', ({spent}) => s
|
|
|
206
239
|
take arguments, `perMinute(t)`; the kernel knows each only by its facts (`.facts(...)`, and a library function's
|
|
207
240
|
own), and the Lean export takes them as the hypothesis they are, proving them where the function has a Lean
|
|
208
241
|
definition. A function defined and proven in Lean is how a rule reaches past what the kernel decides: `examples/functions.ts`.
|
|
242
|
+
- **Recurrences and their lemmas** (`recur(name, {args, fns, zero, next}, lemmas, between)`): f(0, a..) = zero and
|
|
243
|
+
f(x + 1, a..) = next(x, f(x, a..), a..), the further arguments `args` (up to four) fixed along the recursion, each term
|
|
244
|
+
the kernel's own or a read of a function in `fns` (`modBy(7)`, another recurrence), the start's too. Each lemma is a law about every x
|
|
245
|
+
and f(x), proven when the function is made, all of them together by induction (the recurrence run as a machine, each
|
|
246
|
+
lemma a law of it, so one lemma may lean on another, and on the facts of the functions it reads); each law `between`
|
|
247
|
+
is about every x <= y and f(x), f(y) ("never shrinks"), proven by induction on y from x, with the lemmas. One that
|
|
248
|
+
isn't proven throws `Unproven` with the induction step it breaks at. The two equations, the lemmas and the laws
|
|
249
|
+
between are the function's facts. The runtimes compute f by the recurrence, continuing from the last value computed at
|
|
250
|
+
the same further arguments (a rule that reads f at a growing count takes one step a request); the Lean export defines
|
|
251
|
+
`Recur.<name>` by it (a function of several arguments through an injective pairing, proven so in Lean) and checks the
|
|
252
|
+
kernel's own proof of every lemma and law between: the machine it was proven by, with its trees, and the run of it that
|
|
253
|
+
reaches x and f(x), so a lemma with a product (squares: f(x) = x·x) needs no tactic of Lean's (`examples/lemmas.ts`).
|
|
209
254
|
- **Liveness** (`rule.leadsTo(name, {from, to, rank, helpful})`, `proveLeadsTo`): whenever `from` holds, `to` holds later in
|
|
210
255
|
every run that takes each helpful request infinitely often; proven by a rank no step raises while waiting and each
|
|
211
256
|
helpful request lowers in its region. `rank` may return several terms (compared in order) and `helpful` may be a list
|
|
@@ -268,7 +313,7 @@ Lean, compiled natively, wins where the state stays small. Details in [`docs/com
|
|
|
268
313
|
| `core/` | Machines, the interpreter and JS compiler, the builders, composition (`compose.ts`), the linear solver and its checker, Houdini invariants, models, the first Lean export |
|
|
269
314
|
| `kernel/` | The trusted kernel and the untrusted prover, with soundness fuzz (`kernel.test.ts`, `history.test.ts`) |
|
|
270
315
|
| `lean-kernel/` | The kernel's Lean twin, its soundness proofs, and the exported trees |
|
|
271
|
-
| `examples/` | The builders at work: `domains/` (187 rules across 21 domains, each with laws and broken variants), `harness.ts` (the triple check), `readme.ts`, `budget.ts`, `gdp.ts` (gdp-ts's example, its checks proven), `composition.ts`, `sets.ts`, `quantifiers.ts`, `functions.ts`, `lists.ts`, `sizes.ts`, `liveness.ts`, `steps.ts` (laws over up to 16 steps), and `jev-fabric/` (a Bend project's 59 proven laws, ported) |
|
|
316
|
+
| `examples/` | The builders at work: `domains/` (187 rules across 21 domains, each with laws and broken variants), `harness.ts` (the triple check), `readme.ts`, `budget.ts`, `gdp.ts` (gdp-ts's example, its checks proven), `datatypes.ts` (records and variants), `lemmas.ts` (recurrences and their lemmas), `composition.ts`, `sets.ts`, `quantifiers.ts`, `functions.ts`, `lists.ts`, `sizes.ts`, `liveness.ts`, `steps.ts` (laws over up to 16 steps), and `jev-fabric/` (a Bend project's 59 proven laws, ported) |
|
|
272
317
|
| `docs/` | The comparison with Bend and Lean, and the full scope |
|
|
273
318
|
| `compare/` | The same three rules in gdp-wired, Bend and plain Lean, checked and measured |
|
|
274
319
|
| `research/` | Everything around the library ([`research/README.md`](research/README.md)): the GPU searches (`search/`, `hw/`, `modal-gpu/`), invariant and rank synthesis (`synth/`), relational laws and guard synthesis (`next/`), bit-vector laws (`sat/`), the enumeration and benchmarks (`enum/`, `gpu/`, `perf/`), the first Lean checker (`lean/`) and the first prototype, the audit path (`audit/`) |
|
package/dist/core/dsl.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type C, type E, type Law, type Machine, type Request, type State } from './machine.js';
|
|
1
|
+
import { type C, type E, type Law, type Recurrence, type Machine, type Request, type State } from './machine.js';
|
|
2
2
|
import { type Goal, type Liveness, type Loop, type StepLaw, type Tree } from '../kernel/kernel.js';
|
|
3
3
|
export type TermLike = Term | number;
|
|
4
4
|
export declare const termOf: (t: TermLike) => E;
|
|
@@ -43,11 +43,17 @@ export declare function when<K extends string>(c: Cond, then: Choice<K>, otherwi
|
|
|
43
43
|
export declare function when(c: Cond, then: Str, otherwise: Str): Str;
|
|
44
44
|
export declare function when<V>(c: Cond, then: Maybe<V>, otherwise: Maybe<V>): Maybe<V>;
|
|
45
45
|
export declare function when(c: Cond, then: Cond, otherwise: Cond): Cond;
|
|
46
|
+
export declare function when<C extends Cases, T extends string>(c: Cond, then: Variant<C, T>, otherwise: Variant<C, T>): Variant<C, T>;
|
|
47
|
+
export declare function when<T extends Record<string, unknown>>(c: Cond, then: T, otherwise: T): T;
|
|
46
48
|
export declare const choose: (c: Cond, then: Cond, otherwise: Cond) => Cond;
|
|
49
|
+
export declare function same(a: unknown, b: unknown): Cond;
|
|
47
50
|
export declare const count: (c: Cond) => Term;
|
|
48
51
|
export declare const sum: (first: TermLike, ...rest: TermLike[]) => Term;
|
|
49
52
|
type Rand = (k: number) => number;
|
|
50
|
-
type Raw = number | boolean | string | null | undefined;
|
|
53
|
+
export type Raw = number | boolean | string | null | undefined | RawObject | readonly Raw[];
|
|
54
|
+
export type RawObject = {
|
|
55
|
+
readonly [field: string]: Raw;
|
|
56
|
+
};
|
|
51
57
|
export type At = string | ((name: string) => string);
|
|
52
58
|
export type Init<V> = {
|
|
53
59
|
readonly kind: Kind<V>;
|
|
@@ -57,7 +63,9 @@ export declare abstract class Kind<V> {
|
|
|
57
63
|
readonly _value: V;
|
|
58
64
|
abstract vars(name: string): string[];
|
|
59
65
|
abstract assume(name: string): Cond[];
|
|
60
|
-
abstract
|
|
66
|
+
abstract build(name: string, get: (part: string) => Term): V;
|
|
67
|
+
value(name: string, at?: At): V;
|
|
68
|
+
invariant(_value: V): Cond[];
|
|
61
69
|
abstract encode(name: string, raw: Raw): Record<string, number>;
|
|
62
70
|
abstract random(name: string, rand: Rand, bound: number): Record<string, number>;
|
|
63
71
|
abstract store(name: string, value: unknown): Record<string, TermLike>;
|
|
@@ -145,6 +153,66 @@ export declare class Maybe<V> {
|
|
|
145
153
|
}): Term;
|
|
146
154
|
}
|
|
147
155
|
export declare const maybe: <V>(of: Kind<V>) => Kind<Maybe<V>>;
|
|
156
|
+
export declare const optional: <V>(c: Cond, value: V) => Maybe<V>;
|
|
157
|
+
type Fields = Record<string, Kind<unknown>>;
|
|
158
|
+
export declare const record: <const K extends Fields>(fields: K) => Kind<ValuesOf<K>>;
|
|
159
|
+
type Cases = Record<string, Fields>;
|
|
160
|
+
type CaseValues<C extends Cases> = {
|
|
161
|
+
[k in keyof C]: ValuesOf<C[k]>;
|
|
162
|
+
};
|
|
163
|
+
type MatchCases<C extends Cases, T> = {
|
|
164
|
+
[k in keyof C]: (fields: ValuesOf<C[k]>) => T;
|
|
165
|
+
};
|
|
166
|
+
export declare class Variant<C extends Cases = Cases, T extends string = 'tag'> {
|
|
167
|
+
readonly tag: Term;
|
|
168
|
+
readonly cases: CaseValues<C>;
|
|
169
|
+
readonly kind: VariantKind<C, T>;
|
|
170
|
+
constructor(tag: Term, cases: CaseValues<C>, kind: VariantKind<C, T>);
|
|
171
|
+
is(k: keyof C & string): Cond;
|
|
172
|
+
match(cases: MatchCases<C, Cond>): Cond;
|
|
173
|
+
match(cases: MatchCases<C, TermLike>): Term;
|
|
174
|
+
match<T>(cases: MatchCases<C, T>): T;
|
|
175
|
+
}
|
|
176
|
+
export type VariantWrite<C extends Cases, T extends string = 'tag'> = {
|
|
177
|
+
[k in keyof C]: {
|
|
178
|
+
[f in T | keyof C[k]]: f extends T ? k : C[k][f] extends Kind<infer V> ? Writes<V> : never;
|
|
179
|
+
};
|
|
180
|
+
}[keyof C];
|
|
181
|
+
export declare class VariantKind<C extends Cases, T extends string = 'tag'> extends Kind<Variant<C, T>> {
|
|
182
|
+
readonly cases: C;
|
|
183
|
+
readonly tagKey: T;
|
|
184
|
+
readonly names: (keyof C & string)[];
|
|
185
|
+
constructor(cases: C, tagKey: T);
|
|
186
|
+
index(k: string): number;
|
|
187
|
+
private payload;
|
|
188
|
+
private filled;
|
|
189
|
+
private at;
|
|
190
|
+
vars(name: string): string[];
|
|
191
|
+
assume(name: string): Cond[];
|
|
192
|
+
build(name: string, get: (part: string) => Term): Variant<C, T>;
|
|
193
|
+
invariant(x: Variant<C, T>): Cond[];
|
|
194
|
+
make(write: VariantWrite<C, T>): Variant<C, T>;
|
|
195
|
+
store(name: string, value: unknown): Record<string, TermLike>;
|
|
196
|
+
decode(name: string, vars: Record<string, number>): {
|
|
197
|
+
[x: string]: (keyof C & string) | Raw;
|
|
198
|
+
};
|
|
199
|
+
empty(): {
|
|
200
|
+
[x: string]: (keyof C & string) | Raw;
|
|
201
|
+
};
|
|
202
|
+
encode(name: string, raw: Raw): {
|
|
203
|
+
[x: string]: number;
|
|
204
|
+
};
|
|
205
|
+
random(name: string, rand: Rand, bound: number): {
|
|
206
|
+
[x: string]: number;
|
|
207
|
+
};
|
|
208
|
+
sample(rand: Rand, bound: number): {
|
|
209
|
+
[x: string]: (keyof C & string) | Raw;
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
export declare function variant<const C extends Cases>(cases: C): VariantKind<C>;
|
|
213
|
+
export declare function variant<const C extends Cases, const T extends string>(cases: C, opts: {
|
|
214
|
+
tag: T;
|
|
215
|
+
}): VariantKind<C, T>;
|
|
148
216
|
export declare const intern: ((text: string) => number) & {
|
|
149
217
|
load(entries: [string, number][]): void;
|
|
150
218
|
};
|
|
@@ -225,10 +293,46 @@ export declare class ListRef {
|
|
|
225
293
|
within(): Forall;
|
|
226
294
|
increasing(): Forall;
|
|
227
295
|
}
|
|
296
|
+
export type PartsWrite = {
|
|
297
|
+
readonly parts: Record<string, MapWrite>;
|
|
298
|
+
};
|
|
299
|
+
export declare class CellsRef<V> {
|
|
300
|
+
readonly name: string;
|
|
301
|
+
readonly kind: Kind<V>;
|
|
302
|
+
private readonly map;
|
|
303
|
+
constructor(name: string, kind: Kind<V>, map: (part: string) => MapRef);
|
|
304
|
+
at(key: TermLike): V;
|
|
305
|
+
set(key: TermLike, value: Writes<V>): PartsWrite;
|
|
306
|
+
each(f: (key: Term) => Writes<V>): PartsWrite;
|
|
307
|
+
}
|
|
308
|
+
export type ItemsOp = {
|
|
309
|
+
readonly when: Cond;
|
|
310
|
+
readonly parts: Record<string, ListOp>;
|
|
311
|
+
readonly len: TermLike;
|
|
312
|
+
};
|
|
313
|
+
export declare class ItemsRef<V> {
|
|
314
|
+
readonly name: string;
|
|
315
|
+
readonly kind: Kind<V>;
|
|
316
|
+
readonly len: Term;
|
|
317
|
+
private readonly list;
|
|
318
|
+
constructor(name: string, kind: Kind<V>, len: Term, list: (part: string) => ListRef);
|
|
319
|
+
private get names();
|
|
320
|
+
at(i: TermLike): V;
|
|
321
|
+
has(x: V): Cond;
|
|
322
|
+
private op;
|
|
323
|
+
push(x: Writes<V>, when?: Cond): ItemsOp;
|
|
324
|
+
pop(when?: Cond): ItemsOp;
|
|
325
|
+
set(i: TermLike, x: Writes<V>, when?: Cond): ItemsOp;
|
|
326
|
+
insertAt(i: TermLike, x: Writes<V>, when?: Cond): ItemsOp;
|
|
327
|
+
removeAt(i: TermLike, when?: Cond): ItemsOp;
|
|
328
|
+
apply(...ops: ItemsOp[]): Record<string, TermLike | PartsWrite>;
|
|
329
|
+
within(): Forall;
|
|
330
|
+
increasing(by: (x: V) => Term): Forall;
|
|
331
|
+
}
|
|
228
332
|
export type Forall = {
|
|
229
333
|
readonly forall: (key: Term, ...more: Term[]) => Cond;
|
|
230
334
|
};
|
|
231
|
-
export declare function forall(f: (key: Term, key2: Term, key3: Term, key4: Term) => Cond): Forall;
|
|
335
|
+
export declare function forall(f: (key: Term, key2: Term, key3: Term, key4: Term, key5: Term, key6: Term) => Cond): Forall;
|
|
232
336
|
export type Relation = {
|
|
233
337
|
readonly when: Cond;
|
|
234
338
|
readonly holds: Cond;
|
|
@@ -239,7 +343,9 @@ export type FnDef = {
|
|
|
239
343
|
arity: number;
|
|
240
344
|
js: string | ((...args: number[]) => number);
|
|
241
345
|
lean?: string;
|
|
242
|
-
facts?: (f: (...args: TermLike[]) => Term) => Record<string, Cond | Forall>;
|
|
346
|
+
facts?: (f: (...args: TermLike[]) => Term, uses?: Record<string, (...args: TermLike[]) => Term>) => Record<string, Cond | Forall>;
|
|
347
|
+
recur?: Recurrence;
|
|
348
|
+
uses?: Record<string, FnDef>;
|
|
243
349
|
};
|
|
244
350
|
export declare const fn: (arity: number, js: FnDef["js"], opts?: {
|
|
245
351
|
lean?: string;
|
|
@@ -247,16 +353,33 @@ export declare const fn: (arity: number, js: FnDef["js"], opts?: {
|
|
|
247
353
|
}) => FnDef;
|
|
248
354
|
export declare const divBy: (c: number) => FnDef;
|
|
249
355
|
export declare const modBy: (c: number) => FnDef;
|
|
356
|
+
type FnTerm = (...args: TermLike[]) => Term;
|
|
357
|
+
type RecurEnv<A extends string, U> = {
|
|
358
|
+
[a in A]: Term;
|
|
359
|
+
} & {
|
|
360
|
+
[u in keyof U]: FnTerm;
|
|
361
|
+
};
|
|
362
|
+
export type RecurDef<A extends string, U extends Record<string, FnDef>> = {
|
|
363
|
+
args?: readonly A[];
|
|
364
|
+
fns?: U;
|
|
365
|
+
zero: TermLike | ((env: RecurEnv<A, U>) => TermLike);
|
|
366
|
+
next: (x: Term, prev: Term, env: RecurEnv<A, U>) => TermLike;
|
|
367
|
+
};
|
|
368
|
+
export declare const recur: <const A extends string = never, U extends Record<string, FnDef> = {}>(name: string, def: RecurDef<A, U>, lemmas?: Record<string, (x: Term, fx: Term, env: RecurEnv<A, U>) => Cond>, between?: Record<string, (x: Term, fx: Term, y: Term, fy: Term, env: RecurEnv<A, U>) => Cond>) => FnDef & {
|
|
369
|
+
verdict: Verdict;
|
|
370
|
+
};
|
|
250
371
|
type Kinds = Record<string, Kind<unknown>>;
|
|
251
372
|
type ValuesOf<K extends Kinds> = {
|
|
252
373
|
[n in keyof K]: K[n] extends Kind<infer V> ? V : never;
|
|
253
374
|
};
|
|
254
375
|
type Obj = object;
|
|
255
|
-
type Writes<V> = V extends Decimal ? DecimalLike | string : V extends Int ? IntLike : V extends Cond ? Cond | boolean : V extends Choice<infer K> ? Choice<K> | K : V extends Maybe<infer W> ? Maybe<W> | Writes<W> | null : V extends Str ? Str | string : TermLike
|
|
376
|
+
type Writes<V> = V extends Decimal ? DecimalLike | string : V extends Int ? IntLike : V extends Cond ? Cond | boolean : V extends Choice<infer K> ? Choice<K> | K : V extends Maybe<infer W> ? Maybe<W> | Writes<W> | null : V extends Str ? Str | string : V extends Variant<infer C, infer T> ? Variant<C, T> | VariantWrite<C, T> : V extends Term ? TermLike : V extends Record<string, unknown> ? {
|
|
377
|
+
[k in keyof V]: Writes<V[k]>;
|
|
378
|
+
} : TermLike;
|
|
256
379
|
type Update<S extends Obj, M extends Obj> = Partial<{
|
|
257
380
|
[k in keyof S]: Writes<S[k]>;
|
|
258
381
|
} & {
|
|
259
|
-
[k in keyof M]: MapWrite;
|
|
382
|
+
[k in keyof M]: M[k] extends CellsRef<unknown> | ItemsRef<unknown> ? PartsWrite : MapWrite;
|
|
260
383
|
}>;
|
|
261
384
|
type Spec = {
|
|
262
385
|
name: string;
|
|
@@ -265,6 +388,8 @@ type Spec = {
|
|
|
265
388
|
state: [string, number | ((p: never) => TermLike)][];
|
|
266
389
|
maps: [string, number][];
|
|
267
390
|
lists?: string[];
|
|
391
|
+
cells?: [string, Kind<unknown>][];
|
|
392
|
+
items?: [string, Kind<unknown>][];
|
|
268
393
|
kinded?: [string, Kind<unknown>][];
|
|
269
394
|
carried?: string[];
|
|
270
395
|
fns?: [string, FnDef][];
|
|
@@ -293,8 +418,8 @@ export declare class Rule<P extends Obj = {}, I extends Obj = {}, S extends Obj
|
|
|
293
418
|
state<T extends Record<string, number | ((p: P) => TermLike) | Init<unknown>>>(init: T): Rule<P, I, S & {
|
|
294
419
|
[k in keyof T]: T[k] extends Init<infer V> ? V : Term;
|
|
295
420
|
}, M, F, R, Su, Q>;
|
|
296
|
-
maps<T extends Record<string, number
|
|
297
|
-
[k in keyof T]: MapRef;
|
|
421
|
+
maps<T extends Record<string, number | Init<unknown>>>(init: T): Rule<P, I, S, M & {
|
|
422
|
+
[k in keyof T]: T[k] extends Init<infer V> ? CellsRef<V> : MapRef;
|
|
298
423
|
}, F, R, Su, Q>;
|
|
299
424
|
ints<T extends Record<string, number | ((p: P) => IntLike)>>(init: T): Rule<P, I, S & {
|
|
300
425
|
[k in keyof T]: Int;
|
|
@@ -307,6 +432,11 @@ export declare class Rule<P extends Obj = {}, I extends Obj = {}, S extends Obj
|
|
|
307
432
|
}, M & {
|
|
308
433
|
[k in N]: ListRef;
|
|
309
434
|
}, F, R, Su, Q>;
|
|
435
|
+
items<T extends Record<string, Kind<unknown>>>(kinds: T): Rule<P, I, S & {
|
|
436
|
+
[k in keyof T & string as `${k}_len`]: Term;
|
|
437
|
+
}, M & {
|
|
438
|
+
[k in keyof T]: ItemsRef<T[k] extends Kind<infer V> ? V : never>;
|
|
439
|
+
}, F, R, Su, Q>;
|
|
310
440
|
fns<T extends Record<string, FnDef>>(defs: T): Rule<P & {
|
|
311
441
|
[k in keyof T]: (...args: TermLike[]) => Term;
|
|
312
442
|
}, I, S, M, F, R, Su, Q>;
|
|
@@ -332,6 +462,7 @@ export declare class Rule<P extends Obj = {}, I extends Obj = {}, S extends Obj
|
|
|
332
462
|
prune(order: keyof R & string, after: (p: P) => TermLike): Rule<P, I, S, M, F, R, Su, Q>;
|
|
333
463
|
law(name: string, f: (env: P & S & M & Su) => Cond | Forall): Law;
|
|
334
464
|
private lawOf;
|
|
465
|
+
kindLaws(): Law[];
|
|
335
466
|
stepLaw(name: string, then: (before: P & I & S & M & F & Su & Q, after: S & M & Su) => Cond | Forall, when?: (before: P & I & S & M & F & Su & Q) => Cond): StepLaw;
|
|
336
467
|
stepsLaw(name: string, k: number, then: (first: P & I & S & M & F & Su & Q, last: S & M & Su, requests: (I & Q)[]) => Cond | Forall, when?: (before: P & I & S & M & F & Su & Q, j: number) => Cond | undefined): StepLaw;
|
|
337
468
|
leadsTo(name: string, spec: {
|
|
@@ -348,6 +479,7 @@ export declare class Rule<P extends Obj = {}, I extends Obj = {}, S extends Obj
|
|
|
348
479
|
private kindAssumptions;
|
|
349
480
|
private afterEnv;
|
|
350
481
|
private env;
|
|
482
|
+
private composites;
|
|
351
483
|
private names;
|
|
352
484
|
private whatIs;
|
|
353
485
|
private distinct;
|
|
@@ -363,7 +495,7 @@ export declare class Rule<P extends Obj = {}, I extends Obj = {}, S extends Obj
|
|
|
363
495
|
};
|
|
364
496
|
private verdict;
|
|
365
497
|
private crossStep;
|
|
366
|
-
compare<St extends Record<string,
|
|
498
|
+
compare<St extends Record<string, Raw>>(reference: {
|
|
367
499
|
init: (params: {
|
|
368
500
|
[k in keyof P]: Raw;
|
|
369
501
|
}) => St;
|
|
@@ -425,13 +557,28 @@ export type Decision = {
|
|
|
425
557
|
then: C;
|
|
426
558
|
goal: Goal;
|
|
427
559
|
};
|
|
560
|
+
type ResultOf<V> = 0 extends 1 & V ? Term : [V] extends [Cond] ? Cond : [V] extends [Decimal] ? Decimal : [V] extends [Int] ? Int : [V] extends [Choice<infer K>] ? Choice<K> : [V] extends [Str] ? Str : [V] extends [Variant<infer C, infer T>] ? Variant<C, T> : [V] extends [Maybe<infer W>] ? Maybe<ResultOf<W>> : [V] extends [Term | number] ? Term : [V] extends [Record<string, unknown>] ? {
|
|
561
|
+
[f in keyof V]: ResultOf<V[f]>;
|
|
562
|
+
} : Term;
|
|
428
563
|
type Result<T> = {
|
|
429
|
-
[k in keyof T]:
|
|
564
|
+
[k in keyof T]: ResultOf<T[k]>;
|
|
430
565
|
};
|
|
566
|
+
type ValueOf<V> = 0 extends 1 & V ? number : [V] extends [Cond] ? boolean : [V] extends [Choice<infer K>] ? K : [V] extends [Str] ? string : [V] extends [Variant<infer C, infer T>] ? CaseRaw<C, T> : [V] extends [Maybe<infer W>] ? ValueOf<W> | null : [V] extends [Term | number | Int | Decimal] ? number : [V] extends [Record<string, unknown>] ? {
|
|
567
|
+
[f in keyof V]: ValueOf<V[f]>;
|
|
568
|
+
} : number;
|
|
569
|
+
type CaseRaw<C extends Cases, T extends string = 'tag'> = {
|
|
570
|
+
[k in keyof C]: {
|
|
571
|
+
[t in T]: k;
|
|
572
|
+
} & {
|
|
573
|
+
[f in keyof C[k]]: C[k][f] extends Kind<infer V> ? ValueOf<V> : never;
|
|
574
|
+
};
|
|
575
|
+
}[keyof C];
|
|
431
576
|
type Value<T> = {
|
|
432
|
-
[k in keyof T]:
|
|
577
|
+
[k in keyof T]: ValueOf<T[k]>;
|
|
578
|
+
};
|
|
579
|
+
type Field = Term | Cond | Int | Decimal | Choice<string> | Str | Variant<any, any> | Maybe<any> | {
|
|
580
|
+
[f: string]: Field | number;
|
|
433
581
|
};
|
|
434
|
-
type Field = Term | Cond | Int | Decimal | Choice<string> | Str;
|
|
435
582
|
export declare class Fun<P extends Obj = {}, I extends Obj = {}, O extends Obj = {}> {
|
|
436
583
|
private readonly r;
|
|
437
584
|
private readonly out?;
|
|
@@ -524,6 +671,10 @@ export type Verdict = {
|
|
|
524
671
|
why?: string;
|
|
525
672
|
trees?: Record<string, Tree>;
|
|
526
673
|
};
|
|
674
|
+
export declare class Unproven extends Error {
|
|
675
|
+
readonly verdict: Verdict;
|
|
676
|
+
constructor(what: string, verdict: Verdict);
|
|
677
|
+
}
|
|
527
678
|
export declare function proveRule(r: Rule<Obj, Obj, Obj, Obj, Obj, Obj, Obj, Obj>, laws: Law[]): Verdict;
|
|
528
679
|
export declare function proveSteps(r: Rule<Obj, Obj, Obj, Obj, Obj, Obj, Obj, Obj>, laws: Law[], stepLaws: StepLaw[]): Verdict;
|
|
529
680
|
export type { StepLaw };
|