lawspec 0.8.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/WEB.md ADDED
@@ -0,0 +1,144 @@
1
+ # JavaScript and TypeScript backends
2
+
3
+ LawSpec emits ES modules. JavaScript uses `.mjs`; TypeScript uses `.ts` with `.js`
4
+ import paths for NodeNext compilation. Generated data and numeric support belong
5
+ in source directories and do not depend on fast-check. Generated properties use
6
+ fast-check's native generators and shrinkers.
7
+
8
+ ## Native structural values
9
+
10
+ `List a` uses `Array<A>`. `Maybe a` and `Either a b` use named classes and, in
11
+ TypeScript, generic unions from `lawspec_data`. User products and sums likewise
12
+ have named native variant classes. TypeScript retains payload types and nominal
13
+ variant identity, including recursive fields and phantom parameters.
14
+
15
+ `Nullable a` and `Optional a` use tagged `data.Presence<A>` values, preserving
16
+ nested states separately from algebraic `Maybe`. Runtime checks enforce the
17
+ presence kind and payload domain. Scalar and structural presence values both use
18
+ the schema bridge when crossing native adapter boundaries.
19
+
20
+ Checked conversions copy containers, reject sparse arrays and invalid fields,
21
+ validate numeric ranges and machine profiles, and preserve raw text and bytes.
22
+ LawSpec equality follows the schema: NaN differs from itself, signed zeros compare
23
+ equal, and Symbols compare by identity. Ordinary JavaScript object equality is
24
+ not a replacement for structural LawSpec equality.
25
+
26
+ ## Total definitions
27
+
28
+ Checked definitions produce reusable source functions:
29
+
30
+ ```lawspec
31
+ unit example.total
32
+
33
+ definition increment (x :: Int8) :: BigInt is x + 1 end
34
+ ```
35
+
36
+ ```javascript
37
+ import {increment} from './lawspec_definitions/example/total.mjs';
38
+
39
+ const symbols = new Map();
40
+ const result = increment(symbols, 127); // 128n
41
+ ```
42
+
43
+ The TypeScript entry point has `symbols: Map<string, symbol>`, `value0: number`,
44
+ and a `bigint` result. Native signatures preserve lists, products, sums, and
45
+ nested presence payloads. Runtime validation also rejects invalid number ranges,
46
+ fractional primitive inputs, and malformed values from JavaScript callers.
47
+ Failures identify the resolved definition.
48
+
49
+ The first argument shares Symbol fixture identity across calls within an example.
50
+ Equal descriptions in separate contexts do not create equal Symbols. Exact
51
+ integers use bigint; exact Decimal and Rational operations use the scalar runtime
52
+ without passing through Number arithmetic.
53
+
54
+ Public modules live under `lawspec_definitions/`, grouped by unit. Checked logical
55
+ bodies live in `lawspec_definition_bodies`. Both are generated-owned source.
56
+ Properties call the implementations directly; a definition never becomes an
57
+ adapter stub. Ordinary adapters remain user-owned. Support-module collisions and
58
+ bindings that shadow generated global access are rejected before output.
59
+
60
+ Definitions and properties share typed Core expression rendering. Match inputs
61
+ are evaluated once, only the selected branch runs, and Boolean guards
62
+ short-circuit. Totality validation checks structural descent and potentially
63
+ failing operations. Generic definitions specialize to concrete uses. Refined signatures become
64
+ checked contracts, and refinement predicates may call checked definitions.
65
+
66
+ ## Formatting and verification
67
+
68
+ Definition output uses two-space blocks, four-space continuations, single-quoted
69
+ strings, and an 80-column layout. String tokens preserve escaped and raw payloads
70
+ in readable and compact modes. Compact mode removes optional document breaks.
71
+ The public `--minify` path covers runtime, declaration, definition, adapter, and
72
+ test artifacts. `tools/web-formatting-integration.mjs` checks the full bundled
73
+ corpus for formatting rules and readable/compact syntax-tree equivalence. It
74
+ records Prettier differences separately: Prettier's continuation layout is not
75
+ the Google four-space continuation rule used here.
76
+
77
+ `tools/web-definitions-integration.mjs` checks both targets and machine profiles,
78
+ strict TypeScript entry points and rejected assignments, source-only execution,
79
+ recursive properties, incorrect adapters, compact output, custom directories,
80
+ and regeneration protection. The implementation modules pass strict TypeScript
81
+ without `any` or `@ts-nocheck`. Existing schema and numeric runtime TypeScript
82
+ files still use `@ts-nocheck`; their public data declarations and definition
83
+ entry points are checked separately.
84
+
85
+ ## Runtime source formatting
86
+
87
+ The checked-in JavaScript scalar runtime, schema runtime, and fast-check helpers
88
+ use two-space indentation, single quotes, and an 80-column target, formatted with
89
+ Prettier 3.6.2. `node tools/format-web-runtimes.mjs` checks these sources;
90
+ `--write` formats them. Set `LAWSPEC_PRETTIER` to the formatter's `index.mjs` when
91
+ it is not in `.artifacts/formatter-deps/prettier/`. This development tool never
92
+ runs in generated projects or during compiler requests.
93
+
94
+ Run `python3 tools/embed-runtimes.py` after runtime edits, then use `--check` to
95
+ verify that native/WASM source embedding is current. Both JavaScript and
96
+ TypeScript receive the reviewed runtime source, with the existing typed-schema
97
+ constructor annotation and module-extension adjustments for TypeScript.
98
+
99
+
100
+ Internal checked Core definition contracts now run at native and logical entry
101
+ points. Emission proves the obligations first; argument validation precedes
102
+ ordered preconditions, and result validation precedes postconditions. Contract
103
+ binders map explicitly to body inputs and the checked result. Refined source
104
+ signatures now produce these contracts through template proof and specialization.
105
+
106
+ `tools/portable-definition-contract-integration.mjs` exercises Python, JavaScript
107
+ and strict TypeScript with both machine profiles and layouts, without property
108
+ frameworks. It also verifies that deliberately corrupted results are rejected.
109
+ The fixture in `test/DefinitionContractFixture.hs` is shared with the JVM checks.
110
+
111
+
112
+ ## Generated source style checks
113
+
114
+ JavaScript and TypeScript emitters use two-space blocks and four-space
115
+ continuations. The latter follows the [Google JavaScript line-wrapping guide](https://google.github.io/styleguide/jsguide.html#s4.5-line-wrapping).
116
+ Binary operators remain on the preceding line when an expression wraps.
117
+ Generated adapter error messages and tagged scalar values use the shared
118
+ single-quoted JavaScript literal renderer.
119
+
120
+ `tools/web-formatting-integration.mjs` independently parses both output modes
121
+ with TypeScript, compares their syntax trees and literal contents, and checks
122
+ quote choice, binary-operator breaks, continuation and statement-block indentation,
123
+ the 80-column limit, tabs, and trailing
124
+ whitespace. Module imports/re-exports and indivisible source excerpts on their
125
+ own comment line are explicit column exceptions. Ordinary prose and code remain
126
+ subject to the limit. Long scalar string values use escaped concatenated chunks;
127
+ property names remain single tokens. It runs
128
+ both machine profiles for the bundled examples and total-definition fixture.
129
+ Set `LAWSPEC_CORE` to the native compiler; optional `LAWSPEC_TYPESCRIPT` and
130
+ `LAWSPEC_PRETTIER` paths select the cached development tools. Prettier must be
131
+ version 3.6.2. Positional arguments select specification files.
132
+
133
+ Prettier differences are saved for inspection, not treated as an exact Google
134
+ style oracle: its continuation indentation differs from Google's. These checks
135
+ are partial style evidence. Additional indentation cases (such as switch bodies
136
+ and type declarations) and Kotlin formatter acceptance remain tracked in the 0.9 plan; passing this script alone does not
137
+ establish complete style conformance.
138
+
139
+ The development-only runtime formatter (`tools/format-web-runtimes.mjs`) applies
140
+ Prettier layout and then syntax-tree-directed continuation indentation. It verifies
141
+ that JavaScript tokens remain unchanged, retains relative callback block indentation,
142
+ and rejects adjustments inside multiline template literals. It is idempotent and
143
+ checks the resulting 80-column limit. Reviewed runtime source is embedded at build
144
+ time; generated projects never download or invoke these development tools.
package/api.mjs CHANGED
@@ -1,6 +1,12 @@
1
1
  // Generated from LawSpec.Gen. Do not edit.
2
- import { loadCore } from './launcher.mjs';
2
+ import {loadCore} from './launcher.mjs';
3
+
3
4
  export async function createCompiler() {
4
5
  const call = await loadCore();
5
- return { check: (input) => call({ schemaVersion: 3, ...input, method: 'check' }), expand: (input) => call({ schemaVersion: 3, ...input, method: 'expand' }), planGeneration: (input) => call({ schemaVersion: 3, ...input, method: 'planGeneration' }) };
6
+ return {
7
+ check: (input) => call({schemaVersion: 3, ...input, method: 'check'}),
8
+ expand: (input) => call({schemaVersion: 3, ...input, method: 'expand'}),
9
+ planGeneration: (input) =>
10
+ call({schemaVersion: 3, ...input, method: 'planGeneration'}),
11
+ };
6
12
  }
package/bin/lawspec.mjs CHANGED
@@ -23,7 +23,7 @@ for (let i = 0; i < args.length; i++) {
23
23
  if (!args[i + 1] || args[i + 1].startsWith("--"))
24
24
  throw new Error(`Missing value for ${arg}`);
25
25
  options[arg.slice(2)] = args[++i];
26
- } else if (["--dry-run", "--check", "--json"].includes(arg))
26
+ } else if (["--dry-run", "--check", "--json", "--minify"].includes(arg))
27
27
  options[arg.slice(2)] = true;
28
28
  else if (arg.startsWith("--")) throw new Error(`Unknown option: ${arg}`);
29
29
  else positional.push(arg);
@@ -118,7 +118,7 @@ async function init() {
118
118
  const hasBuild = (await readdir(root)).some(
119
119
  (f) => buildFiles.includes(f) || f.endsWith(".cabal"),
120
120
  );
121
- const additions = hasBuild ? {} : templates(language);
121
+ const additions = hasBuild ? {} : templates(language, {minify: options.minify === true});
122
122
  for (const name of Object.keys(additions)) {
123
123
  const file = await safePath(root, name);
124
124
  if ((await readOptional(file)) !== null)
@@ -147,7 +147,7 @@ async function init() {
147
147
  });
148
148
  await atomicWrite(
149
149
  configFile,
150
- JSON.stringify(config, null, 2) + "\n",
150
+ JSON.stringify(config, null, options.minify ? undefined : 2) + "\n",
151
151
  current === null,
152
152
  );
153
153
  output(
@@ -173,13 +173,13 @@ async function main() {
173
173
  }
174
174
  if (!verb || ["help", "--help", "-h"].includes(verb)) {
175
175
  output(
176
- "LawSpec 0.8.0\nUsage: lawspec init --target <language> [--project <directory>]\n lawspec check | doctor | explain <unit>::<law> | generate\n lawspec examples [--target <language>] [--output example_artifacts]\nOptions: --config <path>, --target <language>, --machine-bits <32|64>, --json\nGeneration: --dry-run, --check\nTargets: " +
176
+ "LawSpec 0.9.0\nUsage: lawspec init --target <language> [--project <directory>] [--minify]\n lawspec check | doctor | explain <unit>::<law> | generate\n lawspec examples [--target <language>] [--output example_artifacts]\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.8.0");
182
+ output("0.9.0");
183
183
  return;
184
184
  }
185
185
  if (positional.length > (verb === "explain" ? 1 : 0))
@@ -191,7 +191,7 @@ async function main() {
191
191
  options["dry-run"] ||
192
192
  options.check
193
193
  )
194
- throw new Error("examples supports --target, --output and --json only");
194
+ throw new Error("examples supports --target, --output, --json and --minify only");
195
195
  const result = await generateExamples(options);
196
196
  output(
197
197
  options.json
@@ -207,6 +207,8 @@ async function main() {
207
207
  return;
208
208
  }
209
209
  if (options.output) throw new Error("--output is only supported by examples");
210
+ if (options.minify && !["init", "generate", "examples"].includes(verb))
211
+ throw new Error("--minify applies to init, generate and examples");
210
212
  if (verb === "init") return init();
211
213
  if (!["check", "doctor", "explain", "generate"].includes(verb))
212
214
  throw new Error(`Unknown command: ${verb}`);
@@ -287,6 +289,7 @@ async function main() {
287
289
  target: target.language,
288
290
  sourceDir: target.sourceDir,
289
291
  testDir: target.testDir,
292
+ minify: options.minify === true,
290
293
  }),
291
294
  ).files,
292
295
  );
package/build.json CHANGED
@@ -1,41 +1,112 @@
1
1
  {
2
2
  "version": 1,
3
3
  "compilerSources": [
4
+ "lawspec.cabal",
4
5
  "package.yaml",
6
+ "runtime/LawSpecCodecs.hs",
7
+ "runtime/LawSpecDataStrategies.hs",
8
+ "runtime/LawSpecDataStrategies.java",
9
+ "runtime/LawSpecKotlin.kt",
10
+ "runtime/LawSpecKotlinCodecs.kt",
11
+ "runtime/LawSpecKotlinStrategies.kt",
5
12
  "runtime/LawSpecRuntime.hs",
6
13
  "runtime/LawSpecRuntime.java",
14
+ "runtime/LawSpecSchema.hs",
15
+ "runtime/LawSpecSchema.java",
16
+ "runtime/LawSpecStrategies.kt",
17
+ "runtime/lawspec_codecs.go",
18
+ "runtime/lawspec_data_strategies.go",
19
+ "runtime/lawspec_data_strategies.mjs",
20
+ "runtime/lawspec_data_strategies.py",
7
21
  "runtime/lawspec_runtime.go",
8
22
  "runtime/lawspec_runtime.mjs",
9
23
  "runtime/lawspec_runtime.py",
10
24
  "runtime/lawspec_runtime.rs",
25
+ "runtime/lawspec_schema.go",
26
+ "runtime/lawspec_schema.mjs",
27
+ "runtime/lawspec_schema.py",
11
28
  "runtime/lawspec_strategies.rs",
12
29
  "runtime/rust/Cargo.lock",
13
30
  "runtime/rust/Cargo.toml",
14
31
  "src/LawSpec/Api.hs",
15
32
  "src/LawSpec/Backend.hs",
33
+ "src/LawSpec/Capabilities.hs",
34
+ "src/LawSpec/Code/Doc.hs",
35
+ "src/LawSpec/Code/JavaScript.hs",
16
36
  "src/LawSpec/Common.hs",
17
37
  "src/LawSpec/Compile.hs",
18
38
  "src/LawSpec/Core.hs",
39
+ "src/LawSpec/Core/DefinitionContracts.hs",
40
+ "src/LawSpec/Core/Definitions.hs",
19
41
  "src/LawSpec/Core/Eval.hs",
42
+ "src/LawSpec/Core/Expression.hs",
43
+ "src/LawSpec/Core/Payload.hs",
44
+ "src/LawSpec/Core/PayloadPlan.hs",
45
+ "src/LawSpec/Core/RefinementProof.hs",
46
+ "src/LawSpec/Core/Schema.hs",
20
47
  "src/LawSpec/Core/Semantics.hs",
48
+ "src/LawSpec/Core/Total.hs",
49
+ "src/LawSpec/Core/Totality.hs",
50
+ "src/LawSpec/Core/Types.hs",
21
51
  "src/LawSpec/Core/Validate.hs",
52
+ "src/LawSpec/Core/Value.hs",
22
53
  "src/LawSpec/CoreEmit.hs",
23
54
  "src/LawSpec/CoreNativeScalarEmit.hs",
24
55
  "src/LawSpec/CoreScalarEmit.hs",
56
+ "src/LawSpec/Data.hs",
57
+ "src/LawSpec/DefinitionTotality.hs",
25
58
  "src/LawSpec/Domain.hs",
59
+ "src/LawSpec/Elaboration.hs",
26
60
  "src/LawSpec/Emit.hs",
27
61
  "src/LawSpec/Eval.hs",
28
62
  "src/LawSpec/Frontend.hs",
29
63
  "src/LawSpec/Gen.hs",
64
+ "src/LawSpec/GoData.hs",
65
+ "src/LawSpec/GoDefinitions.hs",
66
+ "src/LawSpec/GoExpr.hs",
67
+ "src/LawSpec/GoProperties.hs",
68
+ "src/LawSpec/GoTestHelpers.hs",
69
+ "src/LawSpec/GoTypeRefs.hs",
70
+ "src/LawSpec/HaskellData.hs",
71
+ "src/LawSpec/HaskellDefinitions.hs",
72
+ "src/LawSpec/HaskellExpr.hs",
73
+ "src/LawSpec/HaskellProperties.hs",
74
+ "src/LawSpec/HaskellTestHelpers.hs",
75
+ "src/LawSpec/HaskellTypeRefs.hs",
76
+ "src/LawSpec/Inference.hs",
77
+ "src/LawSpec/JavaData.hs",
78
+ "src/LawSpec/JavaDefinitions.hs",
79
+ "src/LawSpec/JavaExpr.hs",
80
+ "src/LawSpec/JavaProperties.hs",
81
+ "src/LawSpec/JavaTestHelpers.hs",
82
+ "src/LawSpec/KotlinData.hs",
83
+ "src/LawSpec/KotlinDefinitions.hs",
84
+ "src/LawSpec/KotlinExpr.hs",
85
+ "src/LawSpec/KotlinProperties.hs",
86
+ "src/LawSpec/KotlinTestHelpers.hs",
30
87
  "src/LawSpec/Model.hs",
31
88
  "src/LawSpec/Parser.hs",
89
+ "src/LawSpec/PortableGenerator.hs",
90
+ "src/LawSpec/PortableTestHelpers.hs",
32
91
  "src/LawSpec/Prelude.hs",
33
92
  "src/LawSpec/Public.hs",
93
+ "src/LawSpec/PythonData.hs",
94
+ "src/LawSpec/PythonDefinitions.hs",
95
+ "src/LawSpec/PythonExpr.hs",
96
+ "src/LawSpec/PythonTypes.hs",
34
97
  "src/LawSpec/Refinement.hs",
35
98
  "src/LawSpec/RuntimeSources.hs",
99
+ "src/LawSpec/RustData.hs",
100
+ "src/LawSpec/RustDefinitions.hs",
36
101
  "src/LawSpec/RustEmit.hs",
102
+ "src/LawSpec/RustExpr.hs",
37
103
  "src/LawSpec/Scalar.hs",
104
+ "src/LawSpec/SpecializeDefinitions.hs",
38
105
  "src/LawSpec/Testing.hs",
106
+ "src/LawSpec/WebData.hs",
107
+ "src/LawSpec/WebDefinitions.hs",
108
+ "src/LawSpec/WebExpr.hs",
109
+ "src/LawSpec/WebTypes.hs",
39
110
  "stack.yaml",
40
111
  "stack.yaml.lock",
41
112
  "tools/embed-runtimes.py",
@@ -45,51 +116,122 @@
45
116
  "wasm/lawspec-wasm.cabal"
46
117
  ],
47
118
  "digests": {
48
- "package.yaml": "90923d07cf41977f62a201faf26667ae4fd76de84c6f25ce47917ac92a6a1f4b",
49
- "runtime/LawSpecRuntime.hs": "1c3ca22232c64227717d836a57d375d906f748ecde6b79705944a2319ce5064d",
50
- "runtime/LawSpecRuntime.java": "5637914bd491f75ad0c75fb19d1bec798164295b7bcf9d23e1549e8ebf780d01",
51
- "runtime/lawspec_runtime.go": "62d2041c33760b67db619e0a803501768a505c4dfd9837bca85e158fff81fda9",
52
- "runtime/lawspec_runtime.mjs": "7d0abd53fa45dd9828c10ff2ffa7876162e965e7bb4913f4c460af13e06142fa",
53
- "runtime/lawspec_runtime.py": "7541353effebd133e50cd00a3f4d8999651c93ba751a6d951164b1f390ce0c15",
54
- "runtime/lawspec_runtime.rs": "bf9cf5fa546346a59c85248936395fe11946974ce0bad053aeeaf4e26b6a829d",
55
- "runtime/lawspec_strategies.rs": "a5dcee400574a69a5d2aa066bb8959e366728b3f21a578de84f50feadadf6641",
56
- "runtime/rust/Cargo.lock": "91533e20939436e117c0f09ded695a8a05a86e79efc29fe4b4b93ad8ef1771c8",
57
- "runtime/rust/Cargo.toml": "7ec66cf82dcc73a4a0b4a44d6048b6c3a340897c488aaaace9e8d4bac90b5e0a",
58
- "src/LawSpec/Api.hs": "4810c05d53e370daf7520b9116c34997b7b4ba9c8d3f1a349e2afdb7b1424552",
59
- "src/LawSpec/Backend.hs": "15ba04b69739e3891f73757d9cdc0a29acca6b7f7e067fd11d83d718474d0f20",
60
- "src/LawSpec/Common.hs": "baa849dad0cc6227af334fdc7488389df50c0fe3a74a2ba1d84eb60c6b6edd6e",
61
- "src/LawSpec/Compile.hs": "6c8bcea938f2ec3f83afb348c5ca932d96ce070f4e916fc9233a3a02ffcc89f2",
62
- "src/LawSpec/Core.hs": "27ce2bb1274485cc190e10f8520118d5b381c90ac4ab6343223c46fb3cd10869",
63
- "src/LawSpec/Core/Eval.hs": "87bf2acfdfff1431f1358947044c0474df40b5bc601076f5e5051e089f1d2fa4",
119
+ "lawspec.cabal": "f3372cb64f48514e0e7b16c2ea95636845cdd817b8231e23283b5af8d988fca2",
120
+ "package.yaml": "6f039e41854347b0443378de9b163e541e7f4b77448c8f620199a60d36bafcca",
121
+ "runtime/LawSpecCodecs.hs": "90cb1ed15d7ab664a17a054580c849408d77cfd2b2adcb4a3228b05132caeaca",
122
+ "runtime/LawSpecDataStrategies.hs": "840a316e1a69a862957bbd0f799440fc434240c156a3398e5be6563ecaa70a1b",
123
+ "runtime/LawSpecDataStrategies.java": "7e87c952ed192bf93a4b40f251a097148b7387ce7d505b5bc893cd9d51af3e65",
124
+ "runtime/LawSpecKotlin.kt": "0cf3b7de0406155225ccca33ee3dfdf8f0456c47d577f6be8f1265c13df838cb",
125
+ "runtime/LawSpecKotlinCodecs.kt": "6210f77dbbe24ba2088db48dae5415abf0993fe552fb3a57d29430807efbc297",
126
+ "runtime/LawSpecKotlinStrategies.kt": "2841edc3595f6d291859cc7edd31ea52093acf86d3542f07575784b01f9de237",
127
+ "runtime/LawSpecRuntime.hs": "5ced6a6a86a892ae63a544d4c4a4429bf756a730ea786478d820c8070cc96402",
128
+ "runtime/LawSpecRuntime.java": "c7b7cfc9b7c22b082edee14a52d95ef80ebe01ee56988c22702f629ea24b8a4f",
129
+ "runtime/LawSpecSchema.hs": "9912d9f525426a598f9c03c29cfc7bacf80218f73c9d537d8c1257bae245aa33",
130
+ "runtime/LawSpecSchema.java": "885f5f17a9ea1bdb86915dc184aea25b72c3062d6ddb9605530310540b1cc166",
131
+ "runtime/LawSpecStrategies.kt": "569f7775c0ac44765d05567cbf62d026558ac193c080ca71681ec6ee49c21794",
132
+ "runtime/lawspec_codecs.go": "abc910b8ea65f503b2df2c236250b5398012fe5eaf30f3e91d968e34c0897c1e",
133
+ "runtime/lawspec_data_strategies.go": "37aed9e49a286ea74ad9004c85e2ee4e780c99634735f0b40b0233ac24a41443",
134
+ "runtime/lawspec_data_strategies.mjs": "b39db076de1fc4310633a5271a10b336c56d6b1778c6cd8c2bd937f69e87a97d",
135
+ "runtime/lawspec_data_strategies.py": "542320b8733dea4cef96efcbc0ed65a949a90ca94b1771b0bee5773d06740e9a",
136
+ "runtime/lawspec_runtime.go": "af6ef660387b625b3bb5fcd57f06260c821d4f65eda158db44ad12d66e1d70f8",
137
+ "runtime/lawspec_runtime.mjs": "3b7877c1ee523afba30ed24cd452e2a6126d9e741c7675600e867600d7a73f46",
138
+ "runtime/lawspec_runtime.py": "2f780bc92762eb1115f734a36cc224ae34504929b4ff0ec506735cfa9e3ab02b",
139
+ "runtime/lawspec_runtime.rs": "7ae8afaad638a3d9d6973eebc7cd6daecc8012ec57f3f12ff50cca16e23e15b6",
140
+ "runtime/lawspec_schema.go": "bdfb6f2552bfccf56073d52f7cdbe1d784cba2d956c29762d77df7ad6bba8d67",
141
+ "runtime/lawspec_schema.mjs": "d204852d89aa862fc980225c111064e7c41bce5873c08063472b3da66190530c",
142
+ "runtime/lawspec_schema.py": "bf5c719caec1a91c5720be140ceec2cd01a6a2e0cb9a89c7a9bb05fdeecb34e7",
143
+ "runtime/lawspec_strategies.rs": "74c7b58e5ae119c226cec15b5f12875ba3647e45d4868086543ead6fed3bcc3d",
144
+ "runtime/rust/Cargo.lock": "dd5a3c0ba85579d13e61040334e9b16866124d2e88754948ec7dd512ade026ca",
145
+ "runtime/rust/Cargo.toml": "4bd3bb457970bf8f7af8531fc45fd6b605f995594a3ee0f60f7f1aaf765bb8aa",
146
+ "src/LawSpec/Api.hs": "532960f438214b4ca8a43d8d60777b6086e323f0c54fc7d1bc6bdbf0592ea319",
147
+ "src/LawSpec/Backend.hs": "03c3b0cd62467ca677c88d29d7b12b2ab505cc0076d93d1f48fbddb0e9bcf133",
148
+ "src/LawSpec/Capabilities.hs": "e43d4fc3a4481fbb8aa3ff1c3f41f7e7fca5db01bfe256a30162a45d75a00c1c",
149
+ "src/LawSpec/Code/Doc.hs": "9e3b70f85deb1dcbce385af1d0cd4bea2dfa8a2d806d54745d4bb437406673e5",
150
+ "src/LawSpec/Code/JavaScript.hs": "77bf27dcc210216e4739f68c4709f556f80130ab83b3b9387ac4a2421e790910",
151
+ "src/LawSpec/Common.hs": "107612a8aaa787488413acf9c1a56622004d3bff251db89b99928343e6070883",
152
+ "src/LawSpec/Compile.hs": "0260f0f1dc3d18d2f2e172ab47d603b6e3029ce2948cc0a237ad8277fc64707f",
153
+ "src/LawSpec/Core.hs": "ec081c49e5ccce95f84ded6073f1d8f30298f061dd8b94437d4b00410c57f27c",
154
+ "src/LawSpec/Core/DefinitionContracts.hs": "b7f60f038b231187ecf898e585ae1a8fb1fc113bb55bad6d1bb2660350fd969e",
155
+ "src/LawSpec/Core/Definitions.hs": "52f024fca59661142f70f9aa7dd2cbdb4892e5d3b1ca8079c878c5a1ba667112",
156
+ "src/LawSpec/Core/Eval.hs": "e1ad8af5b240dd99c3b1126408d2be5f9b42b86ca6189ecd3868680a5119d931",
157
+ "src/LawSpec/Core/Expression.hs": "84985f4f685126253d3af7b6b605d80d28fc9aa115bd5e2946f989eeb1355224",
158
+ "src/LawSpec/Core/Payload.hs": "df6a2b250c27c12bb6ac16b84847c52546081d066a3dca7575ed0d743cc13d50",
159
+ "src/LawSpec/Core/PayloadPlan.hs": "f2a7d2dc58c6a0f79707bdc24773bd3aad3a3b8eea2735a8284b2a9f3a4af4a8",
160
+ "src/LawSpec/Core/RefinementProof.hs": "c19fc03e68488357a59897ec38ce3d2efd320c35b405b632af17425d6a18447a",
161
+ "src/LawSpec/Core/Schema.hs": "9a4ec3967803913e6ff43d33e00a1b4b3b8ec0c79dbdbd80ae98101c85bf430f",
64
162
  "src/LawSpec/Core/Semantics.hs": "a9d019433e3b9731f8cd0f65ec0ccc53179824bea58247b72df26760b878c2b6",
65
- "src/LawSpec/Core/Validate.hs": "bd67926c872e190279f3758ad57b45c0f80d5be8381cedc8ac56a5b88b115201",
66
- "src/LawSpec/CoreEmit.hs": "7ba225a262372f61edd6fe2ba0f2dbade44dfa2f767cdbcdd3f4c323eb5e9e7b",
67
- "src/LawSpec/CoreNativeScalarEmit.hs": "f20382952f5854605ae617609c1ff9f5627e5acb134417cf3a67b97054844acb",
68
- "src/LawSpec/CoreScalarEmit.hs": "db564e0cb07c69dee63b7dcb9cd524c30d4e7d658264d72f834adcc9fa05899d",
69
- "src/LawSpec/Domain.hs": "8ad50ad3a37aacb3a429c2d7924279e2a3b973204ce3c5c04c634c1b9ada0151",
163
+ "src/LawSpec/Core/Total.hs": "95d2b19ba7fbfd033295504d31f786815384003b3b4d370776860b423cf079dd",
164
+ "src/LawSpec/Core/Totality.hs": "8f5b5d69f4baaba45301899ef568cbe90133943c3771ba78d492424e9725e7a7",
165
+ "src/LawSpec/Core/Types.hs": "4adf656d17812b68e8bf2d541908c769772cd5bfc9ac7a6c367160a5c40c9212",
166
+ "src/LawSpec/Core/Validate.hs": "0f045241215e068081d6cd7cf451f0166671bae5fffafda71a2e2320e8014c27",
167
+ "src/LawSpec/Core/Value.hs": "f2b2e4d82491e184d60b1217922b25c57a06cbbaecb2cb6f31174af50268fbc9",
168
+ "src/LawSpec/CoreEmit.hs": "868633c03239f12543a357677a273896839a0c044f402477a998b9299557c9cd",
169
+ "src/LawSpec/CoreNativeScalarEmit.hs": "43f1a22e95539b717a4a9c50b159d6b0b3879278fc90992a40dba4503f614c94",
170
+ "src/LawSpec/CoreScalarEmit.hs": "485e51dbe3f4dd2f23fb586737364f83e4af98ab532a1462c8b8451fefdb69ed",
171
+ "src/LawSpec/Data.hs": "9dbeafa120276b114dad790ec69e617f7ad0c632e3c718962f2f7faf8ca327f4",
172
+ "src/LawSpec/DefinitionTotality.hs": "7671b7efb0cac5d796b074d48b2c10940e5bd0b5df082b926aee694903285efa",
173
+ "src/LawSpec/Domain.hs": "222d15f0012ae630802238a6d7e1ee78d1e718b599f5ebb5a1ddc4e8d29d68c3",
174
+ "src/LawSpec/Elaboration.hs": "86e3ef77a977cb1b55985e2939648135acd0c2c015afe76e34e09615d555f53e",
70
175
  "src/LawSpec/Emit.hs": "9f34f5765915a2a12a66a6dca647ddaef9289372956802c6d99cf0cfec447c7a",
71
- "src/LawSpec/Eval.hs": "bbaa50d3febee690c3b09ceb3f2592964cdb458dd1b4c38b6ec68a80f3e077ea",
72
- "src/LawSpec/Frontend.hs": "b483732416f23960f0f03c30079a6db3ba630cf013b38fd6beede08b186585b8",
73
- "src/LawSpec/Gen.hs": "f0a153e05fb0599a7cb2303dd62a269b2561738466c7211efc1927af2d5604b0",
74
- "src/LawSpec/Model.hs": "75cedd730b8e8f7bff2dd39cfe3c1ed8f64e74471f6231248474957df446328f",
75
- "src/LawSpec/Parser.hs": "e64356888d78f02572ff8c0a39b782248dd6a4bb9f0b1e30900f9dc12c3cd946",
176
+ "src/LawSpec/Eval.hs": "b0872ba8a6974463b32776653c2939826a6be87318c15641401f913f6b139de2",
177
+ "src/LawSpec/Frontend.hs": "fbf091b9c96f5b5361dbf4f65819634c0f8526ff98550d97c434c0d47af7839e",
178
+ "src/LawSpec/Gen.hs": "0410d4db3727a7999bc08a581301eb71ab570671e0ebeef7f1570ff76152b0a7",
179
+ "src/LawSpec/GoData.hs": "813770986acac02846e446e02e72f634b328c2c23c083fd3bfafbe236524e8a2",
180
+ "src/LawSpec/GoDefinitions.hs": "09e9e4b60cfea893d35589cd18bc8a6099789d81e0f57ae5cb018bd95bd4838b",
181
+ "src/LawSpec/GoExpr.hs": "da3a7cc0e3d2906886dc44f6b990e72098bb351558bbb31ee335da7382fac58a",
182
+ "src/LawSpec/GoProperties.hs": "c0bbbba3b6d15b14c28095dd5c6f35d30aa70fd5991fe95d6f6642d0f69b1d42",
183
+ "src/LawSpec/GoTestHelpers.hs": "dee55ee8505370e932773b8c685f4a1f380129e6f43f8806bf1e82efb99451b1",
184
+ "src/LawSpec/GoTypeRefs.hs": "7f239f5ac3ac8bd21c8f76c328049f7715d8562ee1382befa0a58abd4f15f726",
185
+ "src/LawSpec/HaskellData.hs": "125d5b8331d4e0a737f5de2fc28cf01677ba7e275b59238416eafdb9b973c809",
186
+ "src/LawSpec/HaskellDefinitions.hs": "535a8d644d5ddb98c22fa6bdf34cf2baa787aa1f5b900815c621d0d65ede0f0f",
187
+ "src/LawSpec/HaskellExpr.hs": "f4144cf2022ef0a3bec6d796ebe7d2f42563e9d25758b9f362cd5545b47e802b",
188
+ "src/LawSpec/HaskellProperties.hs": "770b5047ec35e99ce186b65f22d913e0e117f33a3103d5382176ccf4ec50393a",
189
+ "src/LawSpec/HaskellTestHelpers.hs": "51e59b2abc9e85455e3c8e2c6baadb27e5d319081cb730d2ce56be5dc8053897",
190
+ "src/LawSpec/HaskellTypeRefs.hs": "2225b2a5e2ab3662e7202d23b24f4d6db48353b35ae28df8acd2b92fd2b97574",
191
+ "src/LawSpec/Inference.hs": "78285145897f03c3c4adc37acf0f490ea779bab3975fb2830628dae3a152fe38",
192
+ "src/LawSpec/JavaData.hs": "8f5720812a899e02f7d607a7acef133b7aec4a7617e597700a87e436604e0563",
193
+ "src/LawSpec/JavaDefinitions.hs": "9c0fe11bd4849af09bbe3d941d89ba609a2dabecdc1c8b09b6ddbf69671c8f92",
194
+ "src/LawSpec/JavaExpr.hs": "6f237b0fc1eabe2d53c160f4cb781f8b77b478383f1a77ca4ccc8f08ac0dbcd0",
195
+ "src/LawSpec/JavaProperties.hs": "6cacfc6a005ac93a684e94efbfa7f83619d8658a396722b3fc47e533ba04cac1",
196
+ "src/LawSpec/JavaTestHelpers.hs": "e6f4b9bbb7e5f07ece6ab1845e12aa661e62e8b926680b11454223fc3ec1523d",
197
+ "src/LawSpec/KotlinData.hs": "338f576204e1f30cc0fdf82c806cbffcfbed3a5dfd1b33ac91cde7d975a28360",
198
+ "src/LawSpec/KotlinDefinitions.hs": "97d7d407d4bbdb4ce16035d607dbbcb8e3d6f5db513f2123a2c269e3dc6d2b38",
199
+ "src/LawSpec/KotlinExpr.hs": "20312f0774f1d0832a21a19b93c8103e2791ecd32a827d8e9c4f2b4830a996a0",
200
+ "src/LawSpec/KotlinProperties.hs": "670a5585a552a2ac91922938a859ca437c32fafd085517bdf2ee169b4d6129c2",
201
+ "src/LawSpec/KotlinTestHelpers.hs": "74810d65faafc6ed4d64b1fb0596cda4186e586b7144a7441641b798795bc324",
202
+ "src/LawSpec/Model.hs": "1d7ceb7bd66e3d496eef89eaa86403e6896472317ca9a4be86e0c933a7cce403",
203
+ "src/LawSpec/Parser.hs": "ad11e8f06371e98f295fae0245edceac8142320f054d0c3cb5600bc72588e17e",
204
+ "src/LawSpec/PortableGenerator.hs": "69d457e39f539c77fc7a4c08205e75352bbecd9dfdff031a283a39bf44b22d49",
205
+ "src/LawSpec/PortableTestHelpers.hs": "8ba4d87183c8c11f6ef1ce21c170127335797154f29fb97ad3429f032a167fd3",
76
206
  "src/LawSpec/Prelude.hs": "b1e155c12f58e7c346551a0c65c5d5af76d045b3f1625977ca2a5d1c97cb8c46",
77
- "src/LawSpec/Public.hs": "eec6c9684b3c5cb42fa882f89460104856cb02f963822b66d9b9583dc011dfeb",
78
- "src/LawSpec/Refinement.hs": "9902897edc0a803c2d440cf6d5a1d44e524f94b7384ea55a6f9dcd16dbfa8957",
79
- "src/LawSpec/RuntimeSources.hs": "69dadd138bb784eaebd74869d03e30079e6d73e1724179794d8ec32be178e171",
80
- "src/LawSpec/RustEmit.hs": "702652cc590c5db148f35d2e591d90e45270eee47e78c31772749943509aafe7",
81
- "src/LawSpec/Scalar.hs": "2907d94b72e66584b762b5ab33da64adb26f9bf84b885151ef408dc3de1a440d",
82
- "src/LawSpec/Testing.hs": "a5dc1c15a45539bb72d1c7cb24cbd04888bbb8ef2f066c829654c3bdbf32c609",
207
+ "src/LawSpec/Public.hs": "1b5e6031983cdc81559faea8a9a7e9a7bfab835de90fbf8c89f26844c411563a",
208
+ "src/LawSpec/PythonData.hs": "07e9bb54a1515f3f4744b7b9bb43633cbdbf07b3f9e35efef511753f97e216d5",
209
+ "src/LawSpec/PythonDefinitions.hs": "bc7b971be97339f2d9e4962ad98100878266176aeccd2a9dfd014e2db9550bd8",
210
+ "src/LawSpec/PythonExpr.hs": "23d7d24b5fb4efff9cb63d38c02a93d95744ec79b4565daf1412088fc7c4ba59",
211
+ "src/LawSpec/PythonTypes.hs": "ef928bfeb4324eb6e53c99cae247cc2fa84816075d81de4589d14abaa326656a",
212
+ "src/LawSpec/Refinement.hs": "8058a9f7e433b4b00ef0966a9ea2be3c91ae93b591ed58a1ffcb792d316193d3",
213
+ "src/LawSpec/RuntimeSources.hs": "ca453784dd06b7be37568aa142e402fabf9a572d6144766fabf14677d77d95e8",
214
+ "src/LawSpec/RustData.hs": "08e2c1e2181cbe120362b9fe87881dc78aaa4878c7a7fcec46d1df086b658ae5",
215
+ "src/LawSpec/RustDefinitions.hs": "5d0328a8b17e0cb5067f65d23f0f2cd2a96b92e4b1c3d6e22b7cb08255697177",
216
+ "src/LawSpec/RustEmit.hs": "4fbbf0e81627d477fd42db380cd7ff067c4a8641a9e74957d93ba2f3b0dce79b",
217
+ "src/LawSpec/RustExpr.hs": "04b2ef81417b811c7b98a98acdadab4e588ca8757964a63ba8dc5936c36479e6",
218
+ "src/LawSpec/Scalar.hs": "52e61fec81a337bb5b35e9e6f501446cf0b18bffa6c6af2ddc5aeac2d6e07131",
219
+ "src/LawSpec/SpecializeDefinitions.hs": "08f2fe674a5e00d1be396d9edab0dd2c948b7beb12fa99f2a6aba00cbdf01e33",
220
+ "src/LawSpec/Testing.hs": "db1a427ac2197e447faf2a36eccfe965c58eaa0ba07bc494bf1ba24e4af43ad4",
221
+ "src/LawSpec/WebData.hs": "d32ed71cc09a5715b6fbaf2c5784afc939e2cb61db4b364f7bed98118fd63899",
222
+ "src/LawSpec/WebDefinitions.hs": "fd985db70c778c8014b780666ac327018e05260be610fa717b8c5477ba9638b4",
223
+ "src/LawSpec/WebExpr.hs": "0389dcd5cf7479dd23ef034b1012de6ebd70bf1dc9e3d90981dfb0ba2702596f",
224
+ "src/LawSpec/WebTypes.hs": "f77ffee1e0c7929964a889fb252c1c5d0977afed94664ffcb0f8770c37b98c70",
83
225
  "stack.yaml": "20ccf4d599e355e60b7aa4f814a7cd4299fe2048616cc2e6dbdc22a7bd8cec73",
84
226
  "stack.yaml.lock": "ae222b9c81af920c56e50fa4596fa57786e7fa5a7b461390362b2b2ff63818c7",
85
- "tools/embed-runtimes.py": "26dda6ecf944ac065d10165d84ecdf44f134945fabbd48492a67d2495b5faba4",
227
+ "tools/embed-runtimes.py": "91a05197fc542a65387f3ccf4614a4817c850031eb4b84196c621b8baf344865",
86
228
  "wasm/app/Exports.hs": "4ecbdac8faa2449e6fc61b93c82e6278fa14374154f29b4dacf0eef433f06a47",
87
229
  "wasm/cabal.project": "021e560afdc5eb4cb7169e7119ecb8f92c9ee170245af909c94b612941bff5cc",
88
230
  "wasm/cabal.project.freeze": "733dbed3d2ecccb26e874fd58f136296dad772184deb1658c196b5d54a0814dc",
89
- "wasm/lawspec-wasm.cabal": "22590b2a6fcd384ef8957bd179e04a055e90535f7eaaa2b5ac3d314fd0b686ed",
90
- "npm/core.wasm": "09efa9e767c3d33e718a8a0909cdf23b24d158813570cc610f56e72d37a59fa3",
231
+ "wasm/lawspec-wasm.cabal": "61a21f9fc39087839a0df9781d94c9e7ed3dc375316c06e7dac36bd5e67e7f20",
232
+ "npm/core.wasm": "544ee4b0706f30b73ec6d4d1de1c27da7ebf9838c1dd1b9cff45b7c0393773da",
91
233
  "npm/core_jsffi.js": "88d136efe92f7cff5758c8fec8d9b6bbc9707fe37741cebeeb415fe34ce3d72b",
92
- "npm/api.mjs": "7415fc057ea5f4da68f9d255ce862152d6bc45d6b0053d44f61f9110911ac64b",
93
- "npm/index.d.ts": "d19ecaea0be4ca01c8667a76e1bcfe758fd200d728ef67a44ad14e1b1dd15b72"
234
+ "npm/api.mjs": "6e25bb1f187d073f56badc1cd66c6c7f779cf68f1c5607d702d775c1c8b8a6dd",
235
+ "npm/index.d.ts": "d1348a783a116752c8ff2bf31fc29aab107b1452a516bd7b594153e3620cefcd"
94
236
  }
95
237
  }
package/core.wasm CHANGED
Binary file
@@ -0,0 +1,67 @@
1
+ unit example.collections
2
+
3
+ reverse :: List Int32 -> List Int32
4
+ sort :: List Int32 -> List Int32
5
+ sorted :: List Int32 -> Bool
6
+ permutation :: List Int32 -> List Int32 -> Bool
7
+ echoMaybe :: Maybe (Maybe Bool) -> Maybe (Maybe Bool)
8
+ echoEither :: Either (List Int32) (Maybe Bool) -> Either (List Int32) (Maybe Bool)
9
+ echoNested :: List (Maybe (Either CodeUnit16 Bytes)) -> List (Maybe (Either CodeUnit16 Bytes))
10
+
11
+ law `list involution` (f :: List a -> List a) requires Eq a is
12
+ definition is `involution` f end
13
+ end
14
+
15
+ law `reverse twice restores the list` is
16
+ definition is `list involution` reverse end
17
+ example `ordered input` is
18
+ x = [3, 1, 2]
19
+ expect reverse x = [2, 1, 3]
20
+ end
21
+ example `empty input` is x = [] expect reverse x = [] end
22
+ end
23
+
24
+ law `sorting is idempotent` is
25
+ definition is `idempotent` sort end
26
+ example `duplicates` is x = [3, 1, 3] expect sort x = [1, 3, 3] end
27
+ end
28
+
29
+ law `sort produces sorted output` is
30
+ definition is `for all` (xs :: List Int32) . sorted (sort xs) end
31
+ end
32
+
33
+ law `sort preserves length` is
34
+ definition is `for all` (xs :: List Int32) . prelude.length (sort xs) = prelude.length xs end
35
+ end
36
+
37
+ law `sort preserves elements` is
38
+ definition is `for all` (xs :: List Int32) . permutation (sort xs) xs end
39
+ end
40
+
41
+ law `nonempty reversal preserves length` is
42
+ definition is
43
+ `for all` (xs :: List Int32 where prelude.length xs > 0) .
44
+ prelude.length (reverse xs) = prelude.length xs
45
+ end
46
+ end
47
+
48
+ law `Maybe preserves nested absence` is
49
+ definition is `for all` (x :: Maybe (Maybe Bool)) . echoMaybe x = x end
50
+ example `outer absence` is x = Nothing expect echoMaybe x = Nothing end
51
+ example `inner absence` is x = Just Nothing expect echoMaybe x = Just Nothing end
52
+ example `present` is x = Just (Just true) expect echoMaybe x = Just (Just true) end
53
+ end
54
+
55
+ law `Either preserves branches` is
56
+ definition is `for all` (x :: Either (List Int32) (Maybe Bool)) . echoEither x = x end
57
+ example `left list` is x = Left [3, 1, 3] expect echoEither x = Left [3, 1, 3] end
58
+ example `right absence` is x = Right Nothing expect echoEither x = Right Nothing end
59
+ end
60
+
61
+ law `nested raw values survive` is
62
+ definition is `for all` (xs :: List (Maybe (Either CodeUnit16 Bytes))) . echoNested xs = xs end
63
+ example `surrogate and octets` is
64
+ xs = [Nothing, Just (Left codeUnit16(55296)), Just (Right bytes([0, 255]))]
65
+ expect echoNested xs = [Nothing, Just (Left codeUnit16(55296)), Just (Right bytes([0, 255]))]
66
+ end
67
+ end
@@ -0,0 +1,66 @@
1
+ unit example.data_types
2
+
3
+ type Pair (a :: Type) (b :: Type) is
4
+ Pair
5
+ first :: a
6
+ second :: b
7
+ end
8
+
9
+ type Tree (a :: Type) is
10
+ Leaf value :: a
11
+ Branch children :: List (Tree a)
12
+ end
13
+
14
+ law `products preserve every field` is
15
+ definition is
16
+ `for all` (pair :: Pair Int8 Bool) .
17
+ (match pair with
18
+ | Pair first second -> Pair first second
19
+ end) = pair
20
+ end
21
+ example `maximum integer and false` is
22
+ pair = Pair 127 false
23
+ expect pair = Pair 127 false
24
+ end
25
+ end
26
+
27
+ law `sums preserve constructor identity and payloads` is
28
+ definition is
29
+ `for all` (tree :: Tree Int8) .
30
+ (match tree with
31
+ | Leaf value -> Leaf value
32
+ | Branch children -> Branch children
33
+ end) = tree
34
+ end
35
+ example `nested branches` is
36
+ tree = Branch [Leaf 127, Branch [], Leaf -128]
37
+ expect tree = Branch [Leaf 127, Branch [], Leaf -128]
38
+ end
39
+ end
40
+
41
+
42
+ -- A refined type argument constrains the corresponding stored fields. This
43
+ -- predicate becomes a scoped Core traversal, shared by all eight backends.
44
+ refinement Positive is (value :: Int8 where value > 0) end
45
+
46
+ definition positivePair (value :: Positive) :: Pair Positive Bool is
47
+ Pair value true
48
+ end
49
+
50
+ definition reciprocalFirst (pair :: Pair Positive Bool) :: Rational is
51
+ match pair with
52
+ | Pair first second -> 1 / first
53
+ end
54
+ end
55
+
56
+ law `named payload contracts justify exact division` is
57
+ definition is
58
+ `for all` (value :: Positive) .
59
+ reciprocalFirst (positivePair value) = 1 / value
60
+ end
61
+ example `one half` is
62
+ value = 2
63
+ expect positivePair value = Pair 2 true
64
+ expect reciprocalFirst (positivePair value) = rational(1, 2)
65
+ end
66
+ end