lawspec 0.11.0 → 0.12.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/API-MIGRATION.md CHANGED
@@ -278,3 +278,12 @@ Existing factory files remain untouched. Factory signature changes
278
278
  use the existing `adapterUpdates` reporting channel. See `NATIVE-BINDINGS.md`
279
279
  for grouping, module collision checks, and layout
280
280
  migration behavior.
281
+
282
+ ## Evidence in check results (0.12)
283
+
284
+ Check, expand and generation responses include an additive `evidence` array.
285
+ Each item names the owning unit, the contract `declaration`, the `stage`
286
+ (`precondition` or `postcondition`), a `status` of `proved` or
287
+ `runtime-checked`, a `reason`, and the `claim` as a typed expression. Schemas 3
288
+ and 4 are otherwise unchanged; clients that ignore unknown fields need no
289
+ changes. Generated definition code no longer re-checks proved postconditions.
package/LANGUAGE.md CHANGED
@@ -1,4 +1,4 @@
1
- # LawSpec language and compiler boundary (0.11)
1
+ # LawSpec language and compiler boundary (0.12)
2
2
 
3
3
  LawSpec describes portable laws, concrete examples, and adapter contracts. The
4
4
  compiler is written in Haskell. Rust is an output backend alongside Java, Python,
@@ -182,6 +182,37 @@ shrinking stays within the index on every target. The same planning applies to
182
182
  any user-written measure over declared data whose branches are a constant plus
183
183
  the same measure of that branch's fields.
184
184
 
185
+ ### Proved indices and evidence
186
+
187
+ Checked definitions may return indexed families. The compiler proves their
188
+ result indices statically, so they need no runtime postcondition:
189
+
190
+ ```lawspec
191
+ definition concatV (xs :: Vec n Int8) (ys :: Vec m Int8) :: Vec (n + m) Int8 is
192
+ match xs with
193
+ | VNil -> ys
194
+ | VCons h t -> VCons h (concatV t ys)
195
+ end
196
+ end
197
+ ```
198
+
199
+ The proof uses exact linear arithmetic over the measures. A measure applied to a
200
+ known constructor unfolds to that constructor's equation, so `nOfVec (VCons h t)`
201
+ is `nOfVec t + 1`. Within a match branch, the scrutinee's constructor is known.
202
+ Calls of checked definitions are pure, so equal calls have equal results. A
203
+ recursive call contributes its own signature as the induction hypothesis, and
204
+ natural measures are non-negative. A definition whose result index does not
205
+ follow fails with `definition result refinement could not be proved`.
206
+
207
+ Every contract obligation is recorded with how it is discharged. Definition
208
+ postconditions are `proved`, and generated code omits their runtime checks.
209
+ Definition preconditions guard native callers, and adapter contracts cover
210
+ native code that LawSpec cannot inspect, so both are `runtime-checked`.
211
+ `lawspec check` summarizes the evidence, and the API reports each obligation in
212
+ the `evidence` field. A proved definition is a natural reference model for a
213
+ native adapter, as in `append xs ys = concatV xs ys` in the
214
+ [indexed example](examples/specs/indexed_families.lawspec).
215
+
185
216
  ## Total definitions
186
217
 
187
218
  A unit can supply an implementation as a checked total definition:
@@ -385,20 +416,56 @@ API schema v3 uses separately defined wire views, with lossless tagged scalar
385
416
  values. It does not serialize internal AST constructors. See the
386
417
  [API migration guide](API-MIGRATION.md).
387
418
 
388
- ## Beyond 0.11
389
-
390
- Natural-indexed families are implemented in 0.11 by elaboration to erased data,
391
- measures and refinements. GADTs that refine type arguments, non-linear or
392
- non-natural indices, index equalities between sibling fields (such as perfect
393
- trees whose subtrees share one index), and general dependent types remain future
394
- work. The Core type model distinguishes type arguments from index arguments, but
395
- that representation is not a claim that arbitrary dependent programs are
396
- accepted.
397
- External type bindings and custom generator bindings are implemented in the
398
- 0.10 release; see [the binding reference](NATIVE-BINDINGS.md) for their
399
- interface and acceptance status. They configure native representations alongside
400
- the typed testing plan and do not change source-language typing or equality.
401
- Cross-unit packages remain future work.
419
+ ## Roadmap
420
+
421
+ 0.11 elaborates natural-indexed families to erased data, measures and
422
+ refinements. The Core type model distinguishes type arguments from index
423
+ arguments, but that representation is not a claim that arbitrary dependent
424
+ programs are accepted. External type bindings and custom generator bindings
425
+ (0.10) configure native representations alongside the typed testing plan and do
426
+ not change source-language typing or equality; see
427
+ [the binding reference](NATIVE-BINDINGS.md).
428
+
429
+ ### 0.12 Proof-producing dependent layer (released)
430
+
431
+ - Index equalities in checked definitions are discharged statically. Adapter
432
+ results remain runtime-checked.
433
+ - Linear `Natural` arithmetic over measures is solved exactly, with unfolding
434
+ on known constructors and induction through recursive calls.
435
+ - Evidence is recorded for every contract obligation as `proved` or
436
+ `runtime-checked`, and reported by `lawspec check` and the API.
437
+ - Proved definition postconditions produce no runtime checks.
438
+ - Checked definitions may return indexed families. See
439
+ [proved indices](#proved-indices-and-evidence).
440
+
441
+ Still open, for evaluation in later releases: index equalities between sibling
442
+ fields (perfect trees whose subtrees share one index), non-linear indices, and
443
+ GADTs that refine type arguments.
444
+
445
+ ### 0.13 Wlaschin-style domain modeling primitives
446
+
447
+ - Semantic wrappers and constrained primitives.
448
+ - Make illegal states unrepresentable.
449
+ - Explicit domain workflows and state distinctions.
450
+
451
+ These build on 0.10 native bindings and 0.11 refinements.
452
+
453
+ ### 0.14 Cross-unit imports and packages
454
+
455
+ - Reusable law, type and refinement libraries.
456
+ - Versioning and namespacing, including constructor names scoped to their unit.
457
+ Today every unit compiled together needs distinct constructor names.
458
+ - Publishable behavioral contracts.
459
+
460
+ ### 0.15 Evidence/discharge model
461
+
462
+ Each obligation reports how it was discharged:
463
+
464
+ - `PROVED`: discharged statically, by 0.12 evidence or definition proofs.
465
+ - `EXHAUSTIVELY CHECKED`: every value of a finite domain was checked.
466
+ - `PROPERTY TESTED`: generated cases, examples and boundaries.
467
+ - `RUNTIME CHECKED`: adapter contracts and checked codecs at native boundaries.
468
+ - `ASSUMED / EXTERNAL`: native adapters and bindings taken on trust.
402
469
 
403
470
  ## Generated project formatting
404
471
 
@@ -1045,5 +1045,7 @@ after the empty-parameter changes.
1045
1045
  regeneration protection and packaged installation remain tested.
1046
1046
  - Python follows PEP 8; Rust remains a first-class acceptance target throughout.
1047
1047
 
1048
- GADTs, dependent indices and cross-unit package resolution are subsequent work.
1049
- They are not prerequisites for binding ordinary 0.9 products and sums.
1048
+ Dependent indices shipped as natural-indexed families in 0.11. Proof-producing
1049
+ indices and cross-unit packages are 0.12 and 0.14 on the
1050
+ [roadmap](LANGUAGE.md#roadmap). They are not prerequisites for binding ordinary
1051
+ 0.9 products and sums.
package/PRIMITIVES.md CHANGED
@@ -1,4 +1,4 @@
1
- # LawSpec scalar reference (0.11.0)
1
+ # LawSpec scalar reference (0.12.0)
2
2
 
3
3
  A scalar has a declared domain, checked literals, equality, property inputs, and
4
4
  boundary fixtures. General collections, objects, pointers, and type-only constructs
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **State the law once. Check it everywhere.**
4
4
 
5
- LawSpec 0.11 compiles reusable laws into native property tests, executable examples,
5
+ LawSpec 0.12 compiles reusable laws into native property tests, executable examples,
6
6
  and implementation adapters. The compiler is Haskell, distributed as prebuilt
7
7
  WebAssembly with a Node CLI and an asynchronous, typed JavaScript API.
8
8
 
@@ -60,6 +60,18 @@ index instead of filtering for it. See the
60
60
  [indexed example](examples/specs/indexed_families.lawspec), and the
61
61
  [release notes](RELEASE-0.11.md).
62
62
 
63
+ ## Proved indices and evidence in 0.12
64
+
65
+ LawSpec 0.12 proves the result indices of checked definitions statically, so a
66
+ definition such as `concatV :: Vec n Int8 -> Vec m Int8 -> Vec (n + m) Int8`
67
+ needs no runtime postcondition. Every contract obligation is reported as
68
+ `proved` or `runtime-checked` by `lawspec check` and the API. See
69
+ [proved indices](LANGUAGE.md#proved-indices-and-evidence) and the
70
+ [release notes](RELEASE-0.12.md).
71
+
72
+ Planned: 0.13 domain modeling primitives, 0.14 cross-unit packages, and 0.15
73
+ evidence reporting. See the [roadmap](LANGUAGE.md#roadmap).
74
+
63
75
  ## Install and try it
64
76
 
65
77
  LawSpec has its own [syntax-highlighting grammar and VS Code extension](editors/vscode/README.md)
@@ -69,7 +81,7 @@ support to use it; GitHub currently uses the Haskell fallback.
69
81
  Install [LawSpec from npm](https://www.npmjs.com/package/lawspec):
70
82
 
71
83
  ```sh
72
- npm install --save-dev lawspec@0.11.0
84
+ npm install --save-dev lawspec@0.12.0
73
85
  npx lawspec --version
74
86
  ```
75
87
 
@@ -83,8 +95,8 @@ local dependencies so LawSpec can create its `package.json` and test script:
83
95
  ```sh
84
96
  mkdir lawspec-example
85
97
  cd lawspec-example
86
- npm exec --package=lawspec@0.11.0 -- lawspec init --target javascript
87
- npm install --save-dev lawspec@0.11.0
98
+ npm exec --package=lawspec@0.12.0 -- lawspec init --target javascript
99
+ npm install --save-dev lawspec@0.12.0
88
100
  npx lawspec check
89
101
  npx lawspec explain 'example.atoi_codec::itoa and then atoi yields a'
90
102
  npx lawspec doctor
@@ -294,7 +306,7 @@ reusable laws accept these curried functions, their partial applications, and
294
306
  scalar parameters. Quantified test inputs remain scalar.
295
307
 
296
308
  The prelude defines the following laws. Every row has an executable example in
297
- [algebra.lawspec](https://github.com/brain-fuel/lawspec/blob/v0.11.0/examples/specs/algebra.lawspec), including both sides of every
309
+ [algebra.lawspec](https://github.com/brain-fuel/lawspec/blob/v0.12.0/examples/specs/algebra.lawspec), including both sides of every
298
310
  combined law. `f` and `g` are binary operations, `inverse` is unary, and `e` and
299
311
  `zero` are scalar parameters. All these laws require equality of the element type.
300
312
 
@@ -362,7 +374,7 @@ their entire consequence. Every conjunct is type-checked and emitted. As with
362
374
  existing assertions, the first failure stops that individual test. `and` is now
363
375
  a reserved word.
364
376
 
365
- [Currying examples](https://github.com/brain-fuel/lawspec/blob/v0.11.0/examples/specs/currying.lawspec) demonstrate a four-argument
377
+ [Currying examples](https://github.com/brain-fuel/lawspec/blob/v0.12.0/examples/specs/currying.lawspec) demonstrate a four-argument
366
378
  function partially applied twice, a formatter with four heterogeneous arguments,
367
379
  and composition after partial application. Each example states its exact outputs.
368
380
  Run `node npm/bin/lawspec.mjs examples` after rebuilding to inspect all nine units
@@ -414,7 +426,7 @@ law `valid ports round trip` is
414
426
  end
415
427
  ```
416
428
 
417
- The [complete port example](https://github.com/brain-fuel/lawspec/blob/v0.11.0/examples/specs/parse_port.lawspec)
429
+ The [complete port example](https://github.com/brain-fuel/lawspec/blob/v0.12.0/examples/specs/parse_port.lawspec)
418
430
  defines valid ports as 1–65535, and covers both endpoints, ordinary ports, zero,
419
431
  negative values, and 65536. All explicit `expect` assertions run regardless of
420
432
  the law's condition. A false condition skips only the consequence: invalid ports
@@ -432,7 +444,7 @@ The prelude includes `satisfies predicate` (the predicate holds for every input)
432
444
  and `left inverse when predicate parse render` (the guarded round trip above).
433
445
  These reusable laws preserve the condition and its lexical bindings when expanded.
434
446
  `equivalent` can also compare two predicates, since `Bool` supports equality.
435
- The [Boolean flags example](https://github.com/brain-fuel/lawspec/blob/v0.11.0/examples/specs/boolean_flags.lawspec)
447
+ The [Boolean flags example](https://github.com/brain-fuel/lawspec/blob/v0.12.0/examples/specs/boolean_flags.lawspec)
436
448
  checks that flipping twice restores both `false` and `true`; all targets generate
437
449
  Boolean property inputs and explicit tests for both Boolean boundary values. Java caps Boolean-only JetCheck runs at the number of
438
450
  possible input combinations (up to 100), avoiding generator exhaustion.
@@ -511,7 +523,7 @@ This expands to `for all (x :: Int32) . render (x) = referenceRender (x)`.
511
523
  The example inherits the input name `x` from the prelude. Both functions are
512
524
  user-owned adapter functions; either may delegate to your existing code.
513
525
 
514
- [The complete example](https://github.com/brain-fuel/lawspec/blob/v0.11.0/examples/specs/equivalent.lawspec) compares decimal
526
+ [The complete example](https://github.com/brain-fuel/lawspec/blob/v0.12.0/examples/specs/equivalent.lawspec) compares decimal
515
527
  renderers and two implementations that clamp negative integers to zero. For
516
528
  JavaScript, their adapters can be:
517
529
 
@@ -548,7 +560,7 @@ law `normalizers agree` is
548
560
  end
549
561
  ```
550
562
 
551
- The [slug example](https://github.com/brain-fuel/lawspec/blob/v0.11.0/examples/specs/slug.lawspec)
563
+ The [slug example](https://github.com/brain-fuel/lawspec/blob/v0.12.0/examples/specs/slug.lawspec)
552
564
  compares two implementations of ASCII-space replacement. It includes empty,
553
565
  Unicode and escaped text. Each target uses its native string generator:
554
566
  JetCheck `Generator.stringsOf(Generator.asciiPrintableChars())`, Hypothesis `st.text()`, fast-check `fc.string()`,
@@ -575,7 +587,7 @@ law `canonicalization reaches a fixed point` is
575
587
  end
576
588
  ```
577
589
 
578
- The [canonical URL example](https://github.com/brain-fuel/lawspec/blob/v0.11.0/examples/specs/canonical_url.lawspec)
590
+ The [canonical URL example](https://github.com/brain-fuel/lawspec/blob/v0.12.0/examples/specs/canonical_url.lawspec)
579
591
  uses removal of **all trailing slashes** as a small fixed-point demonstration,
580
592
  not a complete URL canonicalization algorithm. For JavaScript:
581
593
 
@@ -584,7 +596,7 @@ export const canonicalize = value => value.replace(/\/+$/, "");
584
596
  ```
585
597
 
586
598
  Removing just one trailing slash fails the supplied repeated-slash example.
587
- The [mixed-input example](https://github.com/brain-fuel/lawspec/blob/v0.11.0/examples/specs/mixed_inputs.lawspec)
599
+ The [mixed-input example](https://github.com/brain-fuel/lawspec/blob/v0.12.0/examples/specs/mixed_inputs.lawspec)
588
600
  shows `Text` and `Int32` in the same quantified property and executable example.
589
601
  The JavaScript API represents example bindings as typed records whose values use
590
602
  `DataValue`: lossless tagged scalar payloads or structural constructors. Expected results are
@@ -667,7 +679,7 @@ by the JS shim.
667
679
  ## Build and verify
668
680
 
669
681
  For contributors working from a repository checkout, build a local archive with
670
- `npm pack ./npm` and install it with `npm install --save-dev ./lawspec-0.11.0.tgz`.
682
+ `npm pack ./npm` and install it with `npm install --save-dev ./lawspec-0.12.0.tgz`.
671
683
  The package payload lives in `npm/`.
672
684
 
673
685
  ```sh
package/REFINEMENTS.md CHANGED
@@ -1,4 +1,4 @@
1
- # Refinements and abstract integers (0.11.0)
1
+ # Refinements and abstract integers (0.12.0)
2
2
 
3
3
  A refinement restricts a scalar domain with a pure Boolean expression. LawSpec
4
4
  checks concrete examples, generates satisfying input tuples, and checks adapter
@@ -0,0 +1,47 @@
1
+ # LawSpec 0.12.0
2
+
3
+ ## Proved indices
4
+
5
+ Checked definitions may return natural-indexed families, and the compiler
6
+ proves their result indices statically:
7
+
8
+ ```lawspec
9
+ definition concatV (xs :: Vec n Int8) (ys :: Vec m Int8) :: Vec (n + m) Int8 is
10
+ match xs with
11
+ | VNil -> ys
12
+ | VCons h t -> VCons h (concatV t ys)
13
+ end
14
+ end
15
+ ```
16
+
17
+ The totality prover now treats calls of checked definitions as pure linear
18
+ atoms, so equal calls have equal results. A single-argument definition that
19
+ matches on its argument unfolds on a known constructor, so `nOfVec (VCons h t)`
20
+ is `nOfVec t + 1`. Natural measures are non-negative. Together with the existing
21
+ match facts and the induction hypothesis from recursive calls, this proves
22
+ definitions such as `concatV`, and tree flattening through nested calls. It
23
+ rejects definitions whose result indices do not follow, including an unchanged
24
+ length, a dropped element, an extra element and a wrong recursive argument.
25
+
26
+ ## Evidence
27
+
28
+ Every contract obligation is recorded as `proved` or `runtime-checked`.
29
+ Definition postconditions are proved, and generated code on all eight targets no
30
+ longer re-checks them at runtime. Definition preconditions, which guard native
31
+ callers, and adapter contracts remain runtime-checked. `lawspec check` prints a
32
+ summary, and API responses include an additive `evidence` array; see
33
+ [API migration](API-MIGRATION.md#evidence-in-check-results-012).
34
+
35
+ The indexed example now includes proved definitions `concatV` and `flattenV`,
36
+ used as reference models for the native `append` and `flatten` adapters. The
37
+ eight-target acceptance runner executes them in both machine profiles and still
38
+ rejects every index-breaking adapter mutant.
39
+
40
+ ## Compatibility
41
+
42
+ Specifications that compiled with 0.11 compile unchanged. Generated definition
43
+ code omits postcondition checks that are now proved, which changes generated
44
+ output but not behavior. API schemas 3 and 4 are unchanged apart from the
45
+ additive `evidence` field. Index equalities between sibling fields, non-linear
46
+ indices and type-refining GADTs remain open; see the
47
+ [roadmap](LANGUAGE.md#roadmap).
package/bin/lawspec.mjs CHANGED
@@ -173,13 +173,13 @@ async function main() {
173
173
  }
174
174
  if (!verb || ["help", "--help", "-h"].includes(verb)) {
175
175
  output(
176
- "LawSpec 0.11.0\nUsage: lawspec init --target <language> [--project <directory>] [--minify]\n lawspec check | doctor | explain <unit>::<law> | generate\n lawspec examples [--example payments] [--target <language>] [--output <directory>]\nOptions: --config <path>, --target <language>, --machine-bits <32|64>, --json\nGeneration: --dry-run, --check, --minify\nTargets: " +
176
+ "LawSpec 0.12.0\nUsage: lawspec init --target <language> [--project <directory>] [--minify]\n lawspec check | doctor | explain <unit>::<law> | generate\n lawspec examples [--example payments] [--target <language>] [--output <directory>]\nOptions: --config <path>, --target <language>, --machine-bits <32|64>, --json\nGeneration: --dry-run, --check, --minify\nTargets: " +
177
177
  targets.join(", "),
178
178
  );
179
179
  return;
180
180
  }
181
181
  if (verb === "--version") {
182
- output("0.11.0");
182
+ output("0.12.0");
183
183
  return;
184
184
  }
185
185
  if (positional.length > (verb === "explain" ? 1 : 0))
@@ -257,6 +257,12 @@ async function main() {
257
257
  if (config.machineBits !== undefined && ![32, 64].includes(config.machineBits)) throw new Error("machineBits must be 32 or 64");
258
258
  const input = { sources: await sources(config), generation: config.generation, machineBits: options.machineBits ?? config.machineBits ?? 64 };
259
259
  const compiler = await createCompiler();
260
+ // Proved obligations need no runtime check; the rest are enforced at runtime.
261
+ const evidenceSummary = (evidence) => {
262
+ if (!evidence.length) return "";
263
+ const count = (status) => evidence.filter((item) => item.status === status).length;
264
+ return ` Evidence: ${count("proved")} proved, ${count("runtime-checked")} runtime-checked obligation(s).`;
265
+ };
260
266
  if (verb === "check") {
261
267
  const result = diagnostics(await compiler.check(input));
262
268
  for (const target of selected) {
@@ -266,7 +272,7 @@ async function main() {
266
272
  output(
267
273
  options.json
268
274
  ? result
269
- : `Checked ${result.laws.length} law(s).`,
275
+ : `Checked ${result.laws.length} law(s).` + evidenceSummary(result.evidence ?? []),
270
276
  );
271
277
  return;
272
278
  }
package/build.json CHANGED
@@ -39,6 +39,7 @@
39
39
  "src/LawSpec/Core/DefinitionContracts.hs",
40
40
  "src/LawSpec/Core/Definitions.hs",
41
41
  "src/LawSpec/Core/Eval.hs",
42
+ "src/LawSpec/Core/Evidence.hs",
42
43
  "src/LawSpec/Core/Expression.hs",
43
44
  "src/LawSpec/Core/Payload.hs",
44
45
  "src/LawSpec/Core/PayloadPlan.hs",
@@ -127,8 +128,8 @@
127
128
  "wasm/lawspec-wasm.cabal"
128
129
  ],
129
130
  "digests": {
130
- "lawspec.cabal": "e250011f2652a4a00c937de6a46763c51e674859db1bd45228d6c560454fc8ec",
131
- "package.yaml": "012f2333a714b4a4c542245250cdc1a1da3620215dcb5379eda9f3ffc3067fea",
131
+ "lawspec.cabal": "dee4969ade96a065c1a527c557575d4041eedd3ae664eb01ec6b568130c5a1fd",
132
+ "package.yaml": "e92c582f87b1704f80d5e31af7fb6dbe4f56190b8660b55cdb8728ca77efec67",
132
133
  "runtime/LawSpecCodecs.hs": "90cb1ed15d7ab664a17a054580c849408d77cfd2b2adcb4a3228b05132caeaca",
133
134
  "runtime/LawSpecDataStrategies.hs": "cbe9f1946228db1076c19cd3158e8798fe32766cfdbea3f66b63d22d3d217508",
134
135
  "runtime/LawSpecDataStrategies.java": "e3416efe8a0d7b1276cb4d1a8105fd01b1f5f3f02a803bf55d955d9e3ec39095",
@@ -152,8 +153,8 @@
152
153
  "runtime/lawspec_schema.mjs": "60eb4204461eaa2c207fc7c3394014e2a814e4383b7045c065b4dae7c7a202c2",
153
154
  "runtime/lawspec_schema.py": "b6967ef1a33fe6a1a180d5573ec37cd8bb2079c06e961ac2eeb05f23cffcdd07",
154
155
  "runtime/lawspec_strategies.rs": "cac9ca301d4614fff9acfe61e7cc5678fabc044edadfa89ec11599b6780dc5f3",
155
- "runtime/rust/Cargo.lock": "a541c57b690f3ece7c0aecb3aef3f1a991a760d3aa04018a8bec9d4567978170",
156
- "runtime/rust/Cargo.toml": "6929f520456dcb6a702bcf40df08c8caeaee41b304b06deb07f86221d378e940",
156
+ "runtime/rust/Cargo.lock": "614c41fad8f762414ea0e6b1de325e0e919f2f7c6a88d85eaa00ae238dc692d5",
157
+ "runtime/rust/Cargo.toml": "5789d98b6ed2022abf63a4a39aa155981b7819df8d41d86e354ffa7b015bb00b",
157
158
  "src/LawSpec/Api.hs": "392f6e8c1a9ae81a95e219ac071e5b4bea03ee330d63b829036f8f54b2eda8a7",
158
159
  "src/LawSpec/Backend.hs": "03c3b0cd62467ca677c88d29d7b12b2ab505cc0076d93d1f48fbddb0e9bcf133",
159
160
  "src/LawSpec/Capabilities.hs": "e43d4fc3a4481fbb8aa3ff1c3f41f7e7fca5db01bfe256a30162a45d75a00c1c",
@@ -165,6 +166,7 @@
165
166
  "src/LawSpec/Core/DefinitionContracts.hs": "b7f60f038b231187ecf898e585ae1a8fb1fc113bb55bad6d1bb2660350fd969e",
166
167
  "src/LawSpec/Core/Definitions.hs": "52f024fca59661142f70f9aa7dd2cbdb4892e5d3b1ca8079c878c5a1ba667112",
167
168
  "src/LawSpec/Core/Eval.hs": "e1ad8af5b240dd99c3b1126408d2be5f9b42b86ca6189ecd3868680a5119d931",
169
+ "src/LawSpec/Core/Evidence.hs": "de5b2fe0df0d681a2d6430a8c535293d7e084fe287ab47522dc57d2be857c6bf",
168
170
  "src/LawSpec/Core/Expression.hs": "84985f4f685126253d3af7b6b605d80d28fc9aa115bd5e2946f989eeb1355224",
169
171
  "src/LawSpec/Core/Payload.hs": "df6a2b250c27c12bb6ac16b84847c52546081d066a3dca7575ed0d743cc13d50",
170
172
  "src/LawSpec/Core/PayloadPlan.hs": "f2a7d2dc58c6a0f79707bdc24773bd3aad3a3b8eea2735a8284b2a9f3a4af4a8",
@@ -172,7 +174,7 @@
172
174
  "src/LawSpec/Core/Schema.hs": "9a4ec3967803913e6ff43d33e00a1b4b3b8ec0c79dbdbd80ae98101c85bf430f",
173
175
  "src/LawSpec/Core/Semantics.hs": "a9d019433e3b9731f8cd0f65ec0ccc53179824bea58247b72df26760b878c2b6",
174
176
  "src/LawSpec/Core/Total.hs": "95d2b19ba7fbfd033295504d31f786815384003b3b4d370776860b423cf079dd",
175
- "src/LawSpec/Core/Totality.hs": "8f5b5d69f4baaba45301899ef568cbe90133943c3771ba78d492424e9725e7a7",
177
+ "src/LawSpec/Core/Totality.hs": "a96fc3b9e8be5d18997065b9d09c0f8a2ede4d6ed2974b3bf355967986b0e459",
176
178
  "src/LawSpec/Core/Types.hs": "48ed1d197ce7089737895b7279f93437301fcfacff8b3a8dd98ecd7f1cb32b37",
177
179
  "src/LawSpec/Core/Validate.hs": "0f045241215e068081d6cd7cf451f0166671bae5fffafda71a2e2320e8014c27",
178
180
  "src/LawSpec/Core/Value.hs": "f2b2e4d82491e184d60b1217922b25c57a06cbbaecb2cb6f31174af50268fbc9",
@@ -188,14 +190,14 @@
188
190
  "src/LawSpec/Frontend.hs": "fbf091b9c96f5b5361dbf4f65819634c0f8526ff98550d97c434c0d47af7839e",
189
191
  "src/LawSpec/Gen.hs": "c76d00fb1f7e9ed2eed7d387f1cd86cf4d12cc57f007abb0e479043b0ed377e6",
190
192
  "src/LawSpec/GoData.hs": "35efbfdc1079e777d4760069fa2405a9700bbabab7dc7e3c2c5e0757312ea201",
191
- "src/LawSpec/GoDefinitions.hs": "09e9e4b60cfea893d35589cd18bc8a6099789d81e0f57ae5cb018bd95bd4838b",
193
+ "src/LawSpec/GoDefinitions.hs": "3cb55c22f28443fff73e73c59780bf1977ab9260b8d66c7f19d1b94b40d1397e",
192
194
  "src/LawSpec/GoExpr.hs": "da3a7cc0e3d2906886dc44f6b990e72098bb351558bbb31ee335da7382fac58a",
193
195
  "src/LawSpec/GoNativeBinding.hs": "1ad8ea4cec6187c7e6005651c0edeec69e196eb329fb958c833da7751225aa1b",
194
196
  "src/LawSpec/GoProperties.hs": "1eee75d852b0a1f8b6fe2cfb1cd3ed7dc57f44ca0ee137697729e8e1583d85fe",
195
197
  "src/LawSpec/GoTestHelpers.hs": "dee55ee8505370e932773b8c685f4a1f380129e6f43f8806bf1e82efb99451b1",
196
198
  "src/LawSpec/GoTypeRefs.hs": "7f239f5ac3ac8bd21c8f76c328049f7715d8562ee1382befa0a58abd4f15f726",
197
199
  "src/LawSpec/HaskellData.hs": "51374f35de2b1d6c78d15597e41e6f0695fe5fdb040cbb35a7d03d23fa3a3179",
198
- "src/LawSpec/HaskellDefinitions.hs": "535a8d644d5ddb98c22fa6bdf34cf2baa787aa1f5b900815c621d0d65ede0f0f",
200
+ "src/LawSpec/HaskellDefinitions.hs": "bc3664771247547900fc65f62147048238c3aa477154ac69d7a6e7568b05b2dd",
199
201
  "src/LawSpec/HaskellExpr.hs": "f4144cf2022ef0a3bec6d796ebe7d2f42563e9d25758b9f362cd5545b47e802b",
200
202
  "src/LawSpec/HaskellNativeBinding.hs": "9f98aa0c8659b572bd6486a0e29c4692bc6432db8639fa74a09bbf1b771bbfa6",
201
203
  "src/LawSpec/HaskellProperties.hs": "5d64d5f45b86b5bb148383588d69ad717b0e158926b76938cc5cef54ed3adecc",
@@ -204,7 +206,7 @@
204
206
  "src/LawSpec/Indexed.hs": "bfb24a4023517acf9f34e6f3327c5623f0e18b1576e5453a43d7a6cd9e691e00",
205
207
  "src/LawSpec/Inference.hs": "78285145897f03c3c4adc37acf0f490ea779bab3975fb2830628dae3a152fe38",
206
208
  "src/LawSpec/JavaData.hs": "177713377f7a38d69fbfd7891899357fc55782cf1d361f2e9dd5baf8725d4067",
207
- "src/LawSpec/JavaDefinitions.hs": "9c0fe11bd4849af09bbe3d941d89ba609a2dabecdc1c8b09b6ddbf69671c8f92",
209
+ "src/LawSpec/JavaDefinitions.hs": "fc2666e4f9f68b747aa596c0caf0483b9f0a47ec4957bbcd399234e77909588d",
208
210
  "src/LawSpec/JavaExpr.hs": "6f237b0fc1eabe2d53c160f4cb781f8b77b478383f1a77ca4ccc8f08ac0dbcd0",
209
211
  "src/LawSpec/JavaNativeBinding.hs": "8abbae78959a5cb61b7c6ae1c9071e43d10e26c2f421766d431fa18031f87173",
210
212
  "src/LawSpec/JavaProperties.hs": "d953771df667aa193b110dbc898b0936b9ff5a32f6ebc9d2ff25d44a6cd4dfec",
@@ -222,16 +224,16 @@
222
224
  "src/LawSpec/PortableGenerator.hs": "69d457e39f539c77fc7a4c08205e75352bbecd9dfdff031a283a39bf44b22d49",
223
225
  "src/LawSpec/PortableTestHelpers.hs": "8ba4d87183c8c11f6ef1ce21c170127335797154f29fb97ad3429f032a167fd3",
224
226
  "src/LawSpec/Prelude.hs": "b1e155c12f58e7c346551a0c65c5d5af76d045b3f1625977ca2a5d1c97cb8c46",
225
- "src/LawSpec/Public.hs": "1b5e6031983cdc81559faea8a9a7e9a7bfab835de90fbf8c89f26844c411563a",
227
+ "src/LawSpec/Public.hs": "5b986149fd3b6169e4393b8b09e67ddf6923607fb3b6af619a1c9dbd20b0280d",
226
228
  "src/LawSpec/PythonData.hs": "07e9bb54a1515f3f4744b7b9bb43633cbdbf07b3f9e35efef511753f97e216d5",
227
- "src/LawSpec/PythonDefinitions.hs": "bc7b971be97339f2d9e4962ad98100878266176aeccd2a9dfd014e2db9550bd8",
229
+ "src/LawSpec/PythonDefinitions.hs": "30f3d2d71a378e194d62261e0fd1baade5a49ac8b5eaac97578ca015a48ce8e4",
228
230
  "src/LawSpec/PythonExpr.hs": "23d7d24b5fb4efff9cb63d38c02a93d95744ec79b4565daf1412088fc7c4ba59",
229
231
  "src/LawSpec/PythonNativeBinding.hs": "4e35ff8781062d0f614e45ea45f98038c8d609ab78bd671cb0a239eaa9db1690",
230
232
  "src/LawSpec/PythonTypes.hs": "ef928bfeb4324eb6e53c99cae247cc2fa84816075d81de4589d14abaa326656a",
231
233
  "src/LawSpec/Refinement.hs": "8058a9f7e433b4b00ef0966a9ea2be3c91ae93b591ed58a1ffcb792d316193d3",
232
234
  "src/LawSpec/RuntimeSources.hs": "22c9f7e4f977b4f548363f494c9d66edeb4d3247c7a1e7e7cad470b1059019be",
233
235
  "src/LawSpec/RustData.hs": "8fda864335ccb5478c39f56cb714d5275edf36fcbdc2d152bbe94960b644ad98",
234
- "src/LawSpec/RustDefinitions.hs": "5d0328a8b17e0cb5067f65d23f0f2cd2a96b92e4b1c3d6e22b7cb08255697177",
236
+ "src/LawSpec/RustDefinitions.hs": "8c289e2779d7ed623f3578f20974dd9e2016c67734ee1447ed7f4b7c22caedf9",
235
237
  "src/LawSpec/RustEmit.hs": "0687d8589940e7b39daa953c439009d1416eba7da54e9936d2f5595316744d21",
236
238
  "src/LawSpec/RustExpr.hs": "04b2ef81417b811c7b98a98acdadab4e588ca8757964a63ba8dc5936c36479e6",
237
239
  "src/LawSpec/RustNativeBinding.hs": "9d08348da571ac335e335e48c1ad4a67108f7bca54119f5960480e97a6d1da84",
@@ -240,7 +242,7 @@
240
242
  "src/LawSpec/SpecializeDefinitions.hs": "08f2fe674a5e00d1be396d9edab0dd2c948b7beb12fa99f2a6aba00cbdf01e33",
241
243
  "src/LawSpec/Testing.hs": "7b0a2e58bcef24365883b479b6a5af720cc2ac4c217ae23bb771c2621d82aec3",
242
244
  "src/LawSpec/WebData.hs": "919af27be12f63f17762e0c052341ab82dcee5d45951a4fd9c66abead98d1ee0",
243
- "src/LawSpec/WebDefinitions.hs": "fd985db70c778c8014b780666ac327018e05260be610fa717b8c5477ba9638b4",
245
+ "src/LawSpec/WebDefinitions.hs": "d654df765e4bafcb1acdd35058f8a510c2cd81920153c0a75ff1e7e1137c96e5",
244
246
  "src/LawSpec/WebExpr.hs": "0389dcd5cf7479dd23ef034b1012de6ebd70bf1dc9e3d90981dfb0ba2702596f",
245
247
  "src/LawSpec/WebNativeBinding.hs": "465251be1a93d24a775aa57955bb9ec612af7364c53c83017da051f44943eda9",
246
248
  "src/LawSpec/WebTypes.hs": "f77ffee1e0c7929964a889fb252c1c5d0977afed94664ffcb0f8770c37b98c70",
@@ -250,8 +252,8 @@
250
252
  "wasm/app/Exports.hs": "4ecbdac8faa2449e6fc61b93c82e6278fa14374154f29b4dacf0eef433f06a47",
251
253
  "wasm/cabal.project": "021e560afdc5eb4cb7169e7119ecb8f92c9ee170245af909c94b612941bff5cc",
252
254
  "wasm/cabal.project.freeze": "733dbed3d2ecccb26e874fd58f136296dad772184deb1658c196b5d54a0814dc",
253
- "wasm/lawspec-wasm.cabal": "01198a858a300d47ea5a9d766523ab577092add5139d09333dbe6fbbf1834c5b",
254
- "npm/core.wasm": "ecf8b4ee304838dd5ea7d9b708dd6e4c2572f76d60e3ac346b3c740b8f0318e7",
255
+ "wasm/lawspec-wasm.cabal": "1d3eb3b1ab9845896d0207ecd5c2cde6ffdbf1837b79203a5eec49f62d434c34",
256
+ "npm/core.wasm": "7a8d98c77d07bd16dec5d8fcd2488f27eac64daaa82d4d9e1643fd93ae4130bc",
255
257
  "npm/core_jsffi.js": "88d136efe92f7cff5758c8fec8d9b6bbc9707fe37741cebeeb415fe34ce3d72b",
256
258
  "npm/api.mjs": "e93251db289ff0609abaff78ad67f0a9af82508c1141c6a999604f67c56b6e7d",
257
259
  "npm/index.d.ts": "2674f8830bd20a2b9ef7dfa99e183598125b6bcc17e8d454e8f7cca1bbd2c9fe"
package/core.wasm CHANGED
Binary file
@@ -19,6 +19,35 @@ append :: (xs :: Vec n Int8) -> (ys :: Vec m Int8) -> (r :: Vec (n + m) Int8)
19
19
  zip :: (xs :: Vec n Int8) -> (ys :: Vec n Bool) -> (r :: Vec n Bool)
20
20
  flatten :: (tree :: Tree n Int8) -> (r :: Vec n Int8)
21
21
 
22
+ -- Checked definitions whose result indices are proved statically, by
23
+ -- structural induction over the constructor equations. They need no runtime
24
+ -- postcondition, and serve as reference models for the native adapters.
25
+ definition concatV (xs :: Vec n Int8) (ys :: Vec m Int8) :: Vec (n + m) Int8 is
26
+ match xs with
27
+ | VNil -> ys
28
+ | VCons h t -> VCons h (concatV t ys)
29
+ end
30
+ end
31
+
32
+ definition flattenV (tree :: Tree n Int8) :: Vec n Int8 is
33
+ match tree with
34
+ | Tip -> VNil
35
+ | Bin l v r -> concatV (flattenV l) (VCons v (flattenV r))
36
+ end
37
+ end
38
+
39
+ law `append agrees with the proved definition` is
40
+ definition is
41
+ `for all` (xs :: Vec n Int8) (ys :: Vec m Int8) . append xs ys = concatV xs ys
42
+ end
43
+ end
44
+
45
+ law `flatten agrees with the proved definition` is
46
+ definition is
47
+ `for all` (tree :: Tree 4 Int8) . flatten tree = flattenV tree
48
+ end
49
+ end
50
+
22
51
  law `replicate has the requested length` is
23
52
  definition is
24
53
  `for all` (n :: Natural where n < 16) (x :: Int8) . nOfVec (replicate n x) = n
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lawspec",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "State the law once. Check it everywhere.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -8,6 +8,6 @@
8
8
  "bin": { "lawspec": "bin/lawspec.mjs" },
9
9
  "exports": { ".": { "types": "./index.d.ts", "import": "./api.mjs" } },
10
10
  "types": "index.d.ts",
11
- "files": ["*.mjs", "*.json", "index.d.ts", "bin", "core.wasm", "core_jsffi.js", "README.md", "NATIVE-BINDINGS.md", "PRIMITIVES.md", "REFINEMENTS.md", "RUST.md", "JAVA.md", "PYTHON.md", "GO.md", "HASKELL.md", "KOTLIN.md", "WEB.md", "LANGUAGE.md", "API-MIGRATION.md", "RELEASE-0.9.md", "RELEASE-0.10.md", "RELEASE-0.11.md", "LICENSE", "starter.lawspec", "examples"],
11
+ "files": ["*.mjs", "*.json", "index.d.ts", "bin", "core.wasm", "core_jsffi.js", "README.md", "NATIVE-BINDINGS.md", "PRIMITIVES.md", "REFINEMENTS.md", "RUST.md", "JAVA.md", "PYTHON.md", "GO.md", "HASKELL.md", "KOTLIN.md", "WEB.md", "LANGUAGE.md", "API-MIGRATION.md", "RELEASE-0.9.md", "RELEASE-0.10.md", "RELEASE-0.11.md", "RELEASE-0.12.md", "LICENSE", "starter.lawspec", "examples"],
12
12
  "scripts": { "test": "node --test test/*.test.mjs" }
13
13
  }