@fraczak/k 6.10.5 → 7.0.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/CHANGELOG.md +70 -0
- package/CLAUDE.md +1 -1
- package/DOCS/BIG_PICTURE.md +156 -172
- package/DOCS/BINARY_CODEC_STATUS_AND_TODO.md +3 -3
- package/DOCS/CODEC_ARCHITECTURE.md +2 -2
- package/DOCS/DICTIONARY.md +243 -250
- package/DOCS/DIVERGENCE_DETECTION.md +0 -1
- package/DOCS/FILE_FORMATS.md +5 -5
- package/DOCS/KIR_SPECIALIZATION_DESIGN.md +1 -1
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +12 -12
- package/DOCS/PATTERNS.md +17 -17
- package/DOCS/PATTERNS_AND_TYPED_VALUES.md +1 -1
- package/DOCS/REPL.md +9 -19
- package/DOCS/TYPE_DERIVATION.md +2 -8
- package/DOCS/WEB_REPL_REQUIREMENTS.md +8 -8
- package/DOCS/book/01-introduction.md +8 -11
- package/DOCS/book/02-syntax-and-values.md +19 -20
- package/DOCS/book/03-types-as-finite-automata.md +42 -43
- package/DOCS/book/04-partial-functions-and-composition.md +2 -3
- package/DOCS/book/05-typing-filters-and-normalization.md +44 -46
- package/DOCS/book/06-values-in-memory.md +10 -10
- package/DOCS/book/08-operational-semantics-and-execution.md +21 -26
- package/DOCS/book/09-compiler-architecture.md +11 -11
- package/DOCS/book/10-from-ast-to-intermediate-representation.md +6 -7
- package/DOCS/book/14-canonical-serialization.md +2 -2
- package/DOCS/book/appendix-b-incorporating-external-predefined-types-and-functions.md +17 -17
- package/DOCS/book.md +5 -5
- package/Examples/arithmetics.k +49 -153
- package/Examples/bnat.k +13 -13
- package/Examples/byte.k +2 -50
- package/Examples/ieee.k +408 -423
- package/Examples/karatsuba-mult.k +30 -34
- package/Examples/nat.k +5 -6
- package/README.md +54 -49
- package/TODO.md +13 -18
- package/browser/repl-browser.mjs +40 -22
- package/browser/shims/fs.mjs +7 -10
- package/browser/vfs-data.mjs +12 -12
- package/codecs/BINARY_FORMAT.md +4 -4
- package/codecs/POLYMORPHIC_BINARY_FORMAT.md +4 -4
- package/codecs/README.md +6 -6
- package/codecs/ieee.mjs +15 -11
- package/codecs/int.mjs +9 -5
- package/codecs/string-codec.mjs +46 -47
- package/core.k +124 -175
- package/object.mjs +0 -7
- package/package.json +5 -2
- package/parser.jison +2 -41
- package/parser.mjs +55 -95
- package/pretty.mjs +11 -4
- package/repl.mjs +8 -63
- package/scripts/build-repl-html.mjs +18 -49
- package/tests/code-derivation/blowup.mjs +2 -4
- package/tests/code-derivation/bnat.mjs +2 -3
- package/tests/code-derivation/dot.mjs +5 -11
- package/tests/code-derivation/nat.mjs +2 -2
- package/tests/code-derivation/not-not.mjs +6 -6
- package/tests/code-derivation/pattern-envelope.mjs +4 -6
- package/tests/code-derivation/product.mjs +3 -6
- package/tests/code-derivation/rlz.mjs +4 -5
- package/tests/test-codecs.mjs +1 -1
- package/tests/test-fingerprint.mjs +36 -41
- package/tests/test-hash-normalization.mjs +4 -6
- package/tests/test-ieee-arithmetic.mjs +6 -7
- package/tests/test-k-object.mjs +11 -15
- package/tests/test-kir.mjs +0 -1
- package/tests/test-kvm-polymorphic.mjs +1 -2
- package/tests/test-kvm.mjs +8 -11
- package/tests/test-repl-html.mjs +86 -9
- package/tests/test-repl.mjs +38 -53
- package/tests/test.mjs +2 -3
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
# Chapter 3 —
|
|
1
|
+
# Chapter 3 — Schemas as Finite Automata
|
|
2
2
|
|
|
3
3
|
## **3.1 Motivation**
|
|
4
4
|
|
|
5
|
-
A
|
|
5
|
+
A schema in `k` describes a set of finite labeled trees, which can be recognized by a finite tree automaton (FTA). Equivalently, a schema definition can be seen as a context-free grammar (CFG), where the payloads of the schema are the derivation trees of the grammar.
|
|
6
6
|
|
|
7
|
-
For example, the recursive
|
|
7
|
+
For example, the recursive schema of a `list`:
|
|
8
8
|
|
|
9
9
|
```k-lang
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
bool = ?< {} true, {} false >;
|
|
11
|
+
list = ?< {} nil, { < {} true, {} false > head, L tail } cons > = L;
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
corresponds to the following 4-rule grammar:
|
|
@@ -20,7 +20,7 @@ corresponds to the following 4-rule grammar:
|
|
|
20
20
|
4: <list> ::= { <bool> head, <list> tail } |cons
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
A
|
|
23
|
+
A payload of schema `list` is a derivation tree of this grammar. For instance, a list containing a single boolean value `true` can be represented by the following derivation:
|
|
24
24
|
|
|
25
25
|
```
|
|
26
26
|
<list>
|
|
@@ -31,25 +31,25 @@ A value of type `list` is a derivation tree of this grammar. For instance, a lis
|
|
|
31
31
|
-- (rule 1) --> {} |true
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
This derivation tree corresponds to the
|
|
34
|
+
This derivation tree corresponds to the payload generated by the constant relation `{ {} |true head, {} |nil tail } |cons`.
|
|
35
35
|
|
|
36
|
-
Representing
|
|
36
|
+
Representing schemas as automata (or CFGs) provides each schema with a well-defined structure, independent of the names used in the source code. This allows for canonical normal forms and for comparing schemas for equality by structure alone.
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
40
40
|
## **3.2 States and Transitions**
|
|
41
41
|
|
|
42
|
-
Each
|
|
42
|
+
Each schema structure introduces one or more *states* in the automaton. A union or a product schema corresponds to a state, and the variants or fields correspond to transitions to other states.
|
|
43
43
|
|
|
44
|
-
For example, consider the
|
|
44
|
+
For example, consider the `bool` schema:
|
|
45
45
|
|
|
46
46
|
```k-lang
|
|
47
|
-
|
|
47
|
+
bool = ?< {} true, {} false >;
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
This
|
|
50
|
+
This schema translates to an automaton with two states:
|
|
51
51
|
|
|
52
|
-
- A root state, let's call it `C0`, representing the
|
|
52
|
+
- A root state, let's call it `C0`, representing the `bool` schema itself (a union).
|
|
53
53
|
- A state `C1` representing the empty product `{}`.
|
|
54
54
|
|
|
55
55
|
From the root state `C0`, there are two transitions:
|
|
@@ -57,46 +57,45 @@ From the root state `C0`, there are two transitions:
|
|
|
57
57
|
- A transition labeled `true` to state `C1`.
|
|
58
58
|
- A transition labeled `false` to state `C1`.
|
|
59
59
|
|
|
60
|
-
`C0` is the root state of the
|
|
60
|
+
`C0` is the root state of the schema, and `C1` is a leaf state, representing an empty unit value.
|
|
61
61
|
|
|
62
62
|
---
|
|
63
63
|
|
|
64
64
|
## **3.3 Canonical Form**
|
|
65
65
|
|
|
66
|
-
Different
|
|
66
|
+
Different schema expressions can describe the same automaton. For example:
|
|
67
67
|
|
|
68
68
|
```k-lang
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
$ pair2 = { < {} true, {} false > x, bool y };
|
|
69
|
+
pair = ?{ < {} false, {} true > x, < {} false, {} true > y };
|
|
70
|
+
pair2 = ?{ < {} true, {} false > x, < {} true, {} false > y };
|
|
72
71
|
```
|
|
73
72
|
|
|
74
|
-
The
|
|
73
|
+
The schemas `pair` and `pair2` are structurally equivalent because the choice order in a union does not alter the underlying accepted set of trees. Canonicalization is the process of removing these superficial differences by erasing local names and renumbering states to produce a single stable representation for each unique schema structure.
|
|
75
74
|
|
|
76
|
-
The canonical form is generated by traversing the
|
|
75
|
+
The canonical form is generated by traversing the schema's graph structure starting from its root state. The process ensures a unique representation by following a consistent ordering:
|
|
77
76
|
|
|
78
|
-
1. **Start at the Root**: Assign the number `C0` to the root state of the
|
|
77
|
+
1. **Start at the Root**: Assign the number `C0` to the root state of the schema.
|
|
79
78
|
2. **Explore Neighbors**: Visit all states reachable from `C0`. Sort the transitions alphabetically by their labels (field or variant names) and assign consecutive numbers (`C1`, `C2`, ...) to the destination states in that order.
|
|
80
79
|
3. **Iterate**: Move to the next state in the numbered sequence (`C1`, then `C2`, etc.) and repeat the process for any of its neighbors that have not yet been numbered.
|
|
81
80
|
4. **Complete**: Continue until all reachable states have been assigned a unique number.
|
|
82
81
|
|
|
83
|
-
This traversal produces a unique and deterministic numbering for any finite directed graph, ensuring that any two structurally identical
|
|
82
|
+
This traversal produces a unique and deterministic numbering for any finite directed graph, ensuring that any two structurally identical schemas will have the exact same canonical representation.
|
|
84
83
|
|
|
85
84
|
---
|
|
86
85
|
|
|
87
86
|
## **3.4 Examples**
|
|
88
87
|
|
|
89
|
-
For a
|
|
88
|
+
For a schema representing binary natural numbers:
|
|
90
89
|
|
|
91
90
|
```k-lang
|
|
92
|
-
|
|
91
|
+
bnat = ?< Bnat 0, Bnat 1, {} _ > = Bnat;
|
|
93
92
|
```
|
|
94
93
|
|
|
95
|
-
the canonical form is:
|
|
94
|
+
the canonical automaton form is:
|
|
96
95
|
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
```text
|
|
97
|
+
C0 = < C0 "0", C0 "1", C1 "_" >;
|
|
98
|
+
C1 = {};
|
|
100
99
|
```
|
|
101
100
|
|
|
102
101
|
The automaton has two states. `C0` is a recursive state that recognizes sequences of "0"s and "1"s, while `C1` is the terminal state, marked by the "_" transition.
|
|
@@ -105,52 +104,52 @@ The automaton has two states. `C0` is a recursive state that recognizes sequence
|
|
|
105
104
|
|
|
106
105
|
## **3.5 Normalization Process**
|
|
107
106
|
|
|
108
|
-
When compiling a program, the following steps are taken to normalize
|
|
107
|
+
When compiling a program, the following steps are taken to normalize schemas:
|
|
109
108
|
|
|
110
|
-
1. **Collect**: Gather all
|
|
111
|
-
2. **Expand**: Recursively replace
|
|
112
|
-
3. **Deduplicate**: Eliminate duplicate
|
|
113
|
-
4. **Canonicalize**: Assign stable state numbers to the unique
|
|
109
|
+
1. **Collect**: Gather all schema structures and filters from the program.
|
|
110
|
+
2. **Expand**: Recursively replace named relation references with their underlying schema structures until only products and unions remain.
|
|
111
|
+
3. **Deduplicate**: Eliminate duplicate schema structures by comparing them structurally.
|
|
112
|
+
4. **Canonicalize**: Assign stable state numbers to the unique schemas to produce their canonical text representation.
|
|
114
113
|
|
|
115
|
-
This process is deterministic, ensuring that the same
|
|
114
|
+
This process is deterministic, ensuring that the same schema structure always produces the exact same canonical form.
|
|
116
115
|
|
|
117
116
|
---
|
|
118
117
|
|
|
119
118
|
## **3.6 Hash-Based Naming**
|
|
120
119
|
|
|
121
|
-
To create a globally unique and stable
|
|
120
|
+
To create a globally unique and stable index for each schema, the compiler computes a digest of its canonical automaton representation. This hash becomes a fixed-width content address for the schema in the registry.
|
|
122
121
|
|
|
123
122
|
For example:
|
|
124
123
|
|
|
125
124
|
```text
|
|
126
|
-
Canonical
|
|
125
|
+
Canonical Automaton: C0=<C0"0",C0"1",C1"_">;C1={}
|
|
127
126
|
↓
|
|
128
127
|
Hash
|
|
129
128
|
↓
|
|
130
129
|
Identifier: @VtPHxGf5GNMzzyVFxtv7gegFfJRYapBGtCeyV56bs5Zb
|
|
131
130
|
```
|
|
132
131
|
|
|
133
|
-
Program objects can
|
|
132
|
+
Program objects and contracts can refer to schemas by their hash-based identifiers (prefixed with `@`) without ambiguity.
|
|
134
133
|
|
|
135
134
|
---
|
|
136
135
|
|
|
137
136
|
## **3.7 Interpretation**
|
|
138
137
|
|
|
139
|
-
The canonical representation of a
|
|
138
|
+
The canonical representation of a schema can be interpreted as:
|
|
140
139
|
|
|
141
140
|
- A finite set of states, `C0…Cn`.
|
|
142
141
|
- Each state is either a product (a record with named fields) or a union (a set of variants).
|
|
143
142
|
- Transitions between states are labeled with strings (field or variant names).
|
|
144
143
|
|
|
145
|
-
Every
|
|
144
|
+
Every payload tree of a given schema is a finite tree that is accepted by this automaton.
|
|
146
145
|
|
|
147
146
|
---
|
|
148
147
|
|
|
149
148
|
## **3.8 Summary**
|
|
150
149
|
|
|
151
|
-
-
|
|
152
|
-
- Every
|
|
153
|
-
- The canonical form eliminates naming differences, providing a single representation for structurally identical
|
|
154
|
-
- Hash-based naming gives each unique
|
|
150
|
+
- Schemas in `k` denote sets of finite, labeled trees.
|
|
151
|
+
- Every schema can be expressed as a finite tree automaton or a context-free grammar.
|
|
152
|
+
- The canonical form eliminates naming differences, providing a single representation for structurally identical schemas.
|
|
153
|
+
- Hash-based naming gives each unique schema a stable and globally unique content-addressable identifier.
|
|
155
154
|
|
|
156
155
|
---
|
|
@@ -82,9 +82,8 @@ Since `k` lacks a direct syntax for literal values, constants are created using
|
|
|
82
82
|
For example, we can define functions that return `true` and `false`:
|
|
83
83
|
|
|
84
84
|
```k-lang
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
false_bool = {} |false $bool ;
|
|
85
|
+
true_bool = {} |true;
|
|
86
|
+
false_bool = {} |false;
|
|
88
87
|
```
|
|
89
88
|
|
|
90
89
|
Here, `true_bool` and `false_bool` are constant functions. They are also **total functions**, meaning they are defined for all inputs. Each function ignores its input and produces a fixed boolean value.
|
|
@@ -1,54 +1,51 @@
|
|
|
1
|
-
# Chapter 5 —
|
|
1
|
+
# Chapter 5 — Schemas, Filters, and Contracts
|
|
2
2
|
|
|
3
|
-
## **5.1
|
|
3
|
+
## **5.1 Filters as partial identity relations**
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
For example, `$ bool` is a partial identity: it returns its argument unchanged when the argument is of type `bool`, and it is undefined otherwise.
|
|
5
|
+
Filters in `k` are introduced by `?` and appear wherever an expression is expected.
|
|
6
|
+
A filter behaves as a partial **identity** relation: it returns its payload unchanged when the payload matches the schema described by the filter, and it is undefined otherwise.
|
|
7
|
+
For example, `? < {} true, {} false >` is a partial identity: it returns its payload unchanged when the payload is a boolean variant, and it is undefined otherwise.
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
An expression may be *restricted* to a type simply by composing it with the corresponding type expression.
|
|
9
|
+
Beyond serving as runtime guards, filters serve as **inductive termination witnesses** that allow contract derivation for recursive relations to converge into finite-state automata.
|
|
12
10
|
|
|
13
11
|
---
|
|
14
12
|
|
|
15
|
-
## **5.2 Filters**
|
|
13
|
+
## **5.2 Filters and Schemas**
|
|
16
14
|
|
|
17
|
-
A **filter** is a syntactic form that denotes a *
|
|
15
|
+
A **filter** is a syntactic form that denotes a *schema graph* — a structural specification of payloads that share a common shape.
|
|
18
16
|
|
|
19
17
|
Filter expressions are introduced by `?` and can be:
|
|
20
18
|
|
|
21
|
-
- **Type expressions** — `? $bool`, `? $< {} x, bool y >`
|
|
22
19
|
- **Product filters** — `? { Filter1 field1, Filter2 field2 }`
|
|
23
20
|
- **Union filters** — `? < Filter1 tag1, Filter2 tag2 >`
|
|
24
|
-
- **Any-
|
|
25
|
-
- **
|
|
26
|
-
- **
|
|
21
|
+
- **Any-schema filter** — `? ( ... )`
|
|
22
|
+
- **Schema variables** — `? X` (local metavariables representing schema graph nodes)
|
|
23
|
+
- **Schema bindings** — `? < X f, (...) = Y g, ... > = X`
|
|
27
24
|
|
|
28
25
|
Filters may contain `...` to indicate that additional fields or tags are allowed:
|
|
29
26
|
`? { Filter1 field1, ... }` matches any product with at least `field1`.
|
|
30
27
|
|
|
31
|
-
The filter `? (...)` matches any
|
|
32
|
-
The filter `? {...}` matches any product
|
|
33
|
-
The filter `? <...>` matches any union
|
|
28
|
+
The filter `? (...)` matches any schema.
|
|
29
|
+
The filter `? {...}` matches any product schema.
|
|
30
|
+
The filter `? <...>` matches any union schema.
|
|
34
31
|
There is no closed unknown filter: use `?{}` for the empty product or `?<>` for the empty union.
|
|
35
32
|
|
|
36
33
|
---
|
|
37
34
|
|
|
38
35
|
## **5.3 Examples of filters**
|
|
39
36
|
|
|
40
|
-
- `?(...)` — represents any
|
|
41
|
-
- `?< (...) f, (...) g >` — represents all union
|
|
42
|
-
- `?{ X f, X g }` — represents all product
|
|
37
|
+
- `?(...)` — represents any schema.
|
|
38
|
+
- `?< (...) f, (...) g >` — represents all union schemas having exactly two variants `f` and `g`.
|
|
39
|
+
- `?{ X f, X g }` — represents all product schemas with two fields `f` and `g`, both of the same schema.
|
|
43
40
|
|
|
44
|
-
A filter constrains where a
|
|
41
|
+
A filter constrains where a relation is defined; it does not alter the output payload once defined.
|
|
45
42
|
|
|
46
43
|
---
|
|
47
44
|
|
|
48
|
-
## **5.4 Recursive filters**
|
|
45
|
+
## **5.4 Recursive schemas and filters**
|
|
49
46
|
|
|
50
47
|
Filters may be recursive.
|
|
51
|
-
They can describe families of recursive
|
|
48
|
+
They can describe families of recursive schemas by defining a metavariable in terms of a filter that references it.
|
|
52
49
|
|
|
53
50
|
Example (list definition):
|
|
54
51
|
|
|
@@ -56,19 +53,19 @@ Example (list definition):
|
|
|
56
53
|
?< {} nil, {X car, Y cdr} cons > = Y
|
|
57
54
|
```
|
|
58
55
|
|
|
59
|
-
This filter states that `Y` is a union
|
|
56
|
+
This filter states that `Y` is a union schema with two variants: `nil` and `cons`.
|
|
60
57
|
|
|
61
58
|
- The `nil` variant holds an empty product `{}`.
|
|
62
|
-
- The `cons` variant is a product with two fields: `car` of some
|
|
59
|
+
- The `cons` variant is a product with two fields: `car` of some schema `X`, and `cdr` of schema `Y` itself.
|
|
63
60
|
|
|
64
|
-
This recursive structure defines a linked list where each element has a `car` (the
|
|
65
|
-
It thus denotes lists of elements of
|
|
61
|
+
This recursive structure defines a linked list where each element has a `car` (the payload) and a `cdr` (the rest of the list).
|
|
62
|
+
It thus denotes lists of elements of schema `X`.
|
|
66
63
|
|
|
67
64
|
---
|
|
68
65
|
|
|
69
|
-
## **5.5
|
|
66
|
+
## **5.5 Schema variables and scope**
|
|
70
67
|
|
|
71
|
-
A
|
|
68
|
+
A schema variable (an identifier, typically starting with an uppercase letter) introduced in a filter is visible within the enclosing relation definition.
|
|
72
69
|
For example:
|
|
73
70
|
|
|
74
71
|
```k-lang
|
|
@@ -77,35 +74,36 @@ car = ?< {} nil, {X car, Y cdr} cons > = Y /cons .car ?X;
|
|
|
77
74
|
|
|
78
75
|
Here:
|
|
79
76
|
|
|
80
|
-
- `X` and `Y` are
|
|
81
|
-
- The filter `?<{}nil,{X car,Y cdr}cons>=Y` constrains the
|
|
82
|
-
- The expression `/cons`
|
|
77
|
+
- `X` and `Y` are schema variables.
|
|
78
|
+
- The filter `?<{}nil,{X car,Y cdr}cons>=Y` constrains the relation `car` to be defined only on inputs that match the recursive list structure.
|
|
79
|
+
- The expression `/cons` asserts the `cons` variant of the union.
|
|
83
80
|
- The expression `.car` accesses the `car` field of a `cons` variant.
|
|
84
|
-
- The final filter `?X` asserts that the result of the field access is of
|
|
81
|
+
- The final filter `?X` asserts that the result of the field access is of schema `X`, the schema of the list's elements.
|
|
85
82
|
|
|
86
83
|
---
|
|
87
84
|
|
|
88
|
-
## **5.6
|
|
85
|
+
## **5.6 Contract derivation and normalization**
|
|
89
86
|
|
|
90
|
-
Every `k`
|
|
87
|
+
Every `k` relation is analyzed by the compiler to derive its **contract**: a connected $(input, output)$ schema graph with shared vertices ($=X$) proving that input substructures are preserved through to the output.
|
|
91
88
|
|
|
92
|
-
|
|
89
|
+
Contract derivation and normalization proceed as follows:
|
|
93
90
|
|
|
94
|
-
1. Build a graph
|
|
95
|
-
2.
|
|
96
|
-
3.
|
|
97
|
-
4.
|
|
98
|
-
5.
|
|
91
|
+
1. Build a schema graph from explicit filters and primitive operations (projections, constructors, products).
|
|
92
|
+
2. Propagate schemas forward and backward through compositions, products, and choices.
|
|
93
|
+
3. Validate inductive convergence for recursive relations using filter witnesses.
|
|
94
|
+
4. Replace filters that match a single, concrete schema with that closed schema, adding any newly discovered schemas to the registry.
|
|
95
|
+
5. Repeat until a fixed point is reached.
|
|
96
|
+
6. Compute canonical forms and content-addressed hashes for all discovered schemas.
|
|
99
97
|
|
|
100
98
|
---
|
|
101
99
|
|
|
102
100
|
## **5.7 Summary**
|
|
103
101
|
|
|
104
|
-
-
|
|
105
|
-
- Filters describe
|
|
106
|
-
- Filters may be products, unions, or the unconstrained any-
|
|
102
|
+
- Filter expressions act as partial identity relations defined on payloads conforming to a schema.
|
|
103
|
+
- Filters describe schema constraints and inductive termination witnesses for recursive relations.
|
|
104
|
+
- Filters may be products, unions, or the unconstrained any-schema form, and can be recursive.
|
|
107
105
|
- Variables in filters have definition-level scope.
|
|
108
|
-
-
|
|
109
|
-
-
|
|
106
|
+
- Contract derivation computes an interconnected $(input, output)$ schema graph for every relation.
|
|
107
|
+
- The canonical form of a schema provides a universal content-addressable identity in the schema registry.
|
|
110
108
|
|
|
111
109
|
---
|
|
@@ -11,7 +11,7 @@ Every `k` value exists in one of three forms during execution:
|
|
|
11
11
|
This unified approach enables programs to operate on serialized inputs without unnecessary deserialization, optimizing performance for identity operations and partial data access patterns.
|
|
12
12
|
|
|
13
13
|
In the current pattern-framed model, every form also has a pattern context. For
|
|
14
|
-
serialized values this is the decoded leading
|
|
14
|
+
serialized values this is the decoded leading `pattern` value; for materialized
|
|
15
15
|
values it is carried on the runtime `Value`. The product/union tree is the
|
|
16
16
|
payload, while the pattern records the polymorphic type information needed to
|
|
17
17
|
interpret and re-encode that payload.
|
|
@@ -111,11 +111,11 @@ Each node in the value tree is encoded based on its automaton state:
|
|
|
111
111
|
|
|
112
112
|
#### **Example: Natural numbers**
|
|
113
113
|
|
|
114
|
-
For type `bnat`, intuitively binary natural numbers defined by
|
|
114
|
+
For type `bnat`, intuitively binary natural numbers defined by `bnat = ?< Bnat 0, Bnat 1, {} _ > = Bnat;`, we get
|
|
115
115
|
|
|
116
116
|
```text
|
|
117
|
-
> :
|
|
118
|
-
|
|
117
|
+
> :rel bnat
|
|
118
|
+
bnat = ?< Bnat 0, Bnat 1, {} _ > = Bnat; -- @...
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
The corresponding Context-Free grammar is:
|
|
@@ -191,7 +191,7 @@ Subtrees that happen to produce the same local payload bits under different type
|
|
|
191
191
|
Consider a binary tree with repeated leaf patterns:
|
|
192
192
|
|
|
193
193
|
```k-lang
|
|
194
|
-
|
|
194
|
+
tree = ?< { T left, T right } branch, int leaf > = T;
|
|
195
195
|
```
|
|
196
196
|
|
|
197
197
|
Value: A tree corresponding to the structure:
|
|
@@ -293,8 +293,8 @@ These are encoder-side construction choices for reaching the same canonical resu
|
|
|
293
293
|
Consider a list of similar records:
|
|
294
294
|
|
|
295
295
|
```k-lang
|
|
296
|
-
|
|
297
|
-
|
|
296
|
+
record = ?{ string name, int age, string department };
|
|
297
|
+
company = ?< { record head, C tail } cons, {} nil > = C;
|
|
298
298
|
```
|
|
299
299
|
|
|
300
300
|
Value representing 1000 employees where 80% work in "Engineering":
|
|
@@ -712,9 +712,9 @@ const Arena = struct {
|
|
|
712
712
|
Consider processing a large JSON-like structure where we only need one field:
|
|
713
713
|
|
|
714
714
|
```k-lang
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
715
|
+
metadata = ?{ timestamp created, string author };
|
|
716
|
+
list = ?< { nat value, L next } cons, {} nil > = L;
|
|
717
|
+
record = ?{ string name, list data, metadata meta };
|
|
718
718
|
```
|
|
719
719
|
|
|
720
720
|
For the input program `\x.x.name` (extract name field):
|
|
@@ -54,16 +54,16 @@ If `v` carries a pattern, the result carries the subpattern reached by `label`.
|
|
|
54
54
|
For a union projection `/label`, the same rule applies to the selected tag's
|
|
55
55
|
payload.
|
|
56
56
|
|
|
57
|
-
### **
|
|
57
|
+
### **Filter expression**
|
|
58
58
|
|
|
59
|
-
For a
|
|
59
|
+
For a pattern filter `?F`,
|
|
60
60
|
|
|
61
61
|
```text
|
|
62
|
-
⟨
|
|
62
|
+
⟨ ?F , v ⟩ ⇓ v if v ∈ L(F)
|
|
63
63
|
```
|
|
64
64
|
|
|
65
65
|
and undefined otherwise.
|
|
66
|
-
|
|
66
|
+
Filter expressions thus act as partial identity functions restricted to their pattern language.
|
|
67
67
|
|
|
68
68
|
---
|
|
69
69
|
|
|
@@ -121,22 +121,19 @@ If no subfunction is defined, the union composition is undefined.
|
|
|
121
121
|
|
|
122
122
|
## **8.7 Rules for filters**
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
A filter `?F` validates that the input value conforms to the pattern:
|
|
125
125
|
|
|
126
126
|
```text
|
|
127
|
-
⟨ ?F , v ⟩ ⇓
|
|
127
|
+
⟨ ?F , v ⟩ ⇓ v if v matches pattern F
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
-
otherwise
|
|
130
|
+
otherwise undefined.
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
As operations they are identities at run time, unless they lead to fully typed
|
|
138
|
-
expressions (i.e., can be replaced by a type). Their pattern information may
|
|
139
|
-
still be present on the runtime value because values can carry codec patterns.
|
|
132
|
+
Filters act as partial identity relations. At compile time, they guide type
|
|
133
|
+
derivation and provide inductive termination witnesses for recursive relations.
|
|
134
|
+
At runtime, filters succeed and preserve the input value when it conforms to
|
|
135
|
+
the pattern, or fail if the value does not match. Their pattern information is
|
|
136
|
+
carried by the runtime value's pattern envelope.
|
|
140
137
|
|
|
141
138
|
---
|
|
142
139
|
|
|
@@ -156,19 +153,17 @@ for any given input, at most one result tree can be produced.
|
|
|
156
153
|
Given:
|
|
157
154
|
|
|
158
155
|
```k-lang
|
|
159
|
-
|
|
160
|
-
neg =
|
|
156
|
+
bool = ?< {} true, {} false >;
|
|
157
|
+
neg = ?< {} true, {} false > < /true | false, /false | true >;
|
|
161
158
|
```
|
|
162
159
|
|
|
163
|
-
and input value `{
|
|
164
|
-
evaluation steps are:
|
|
160
|
+
and input value `{} |true`, evaluation steps are:
|
|
165
161
|
|
|
166
|
-
1. `⟨
|
|
167
|
-
2. `⟨ <
|
|
168
|
-
3. `⟨ $bool , {{ } false} ⟩ ⇓ {{ } false}`
|
|
162
|
+
1. `⟨ ?< {} true, {} false > , {} |true ⟩ ⇓ {} |true`
|
|
163
|
+
2. `⟨ < /true | false, /false | true > , {} |true ⟩ ⇓ {} |false`
|
|
169
164
|
|
|
170
|
-
Final result: `{
|
|
171
|
-
If the input were of another
|
|
165
|
+
Final result: `{} |false`.
|
|
166
|
+
If the input were of another shape, step 1 would be undefined.
|
|
172
167
|
|
|
173
168
|
---
|
|
174
169
|
|
|
@@ -181,7 +176,7 @@ The evaluation rules map directly onto the runtime ABI:
|
|
|
181
176
|
| Projection | `k_project` |
|
|
182
177
|
| Product composition | multiple subcalls + `k_make_product` |
|
|
183
178
|
| Union composition | sequential subcalls with early return |
|
|
184
|
-
|
|
|
179
|
+
| Filter | runtime check or identity |
|
|
185
180
|
| Composition | function call chain |
|
|
186
181
|
|
|
187
182
|
In compiled form, the `ok` flag of `KOpt` represents whether a rule applies;
|
|
@@ -194,7 +189,7 @@ the node pointer represents the result value.
|
|
|
194
189
|
* Execution follows deterministic, left-to-right rules.
|
|
195
190
|
* All expressions denote partial functions on runtime values.
|
|
196
191
|
* Runtime values may carry patterns, and structural operations propagate them.
|
|
197
|
-
*
|
|
192
|
+
* Filter expressions act as restricted identities.
|
|
198
193
|
* Composition is associative; undefined propagates automatically.
|
|
199
194
|
* Runtime semantics match the formal evaluation relation exactly.
|
|
200
195
|
|
|
@@ -73,15 +73,15 @@ These tables ensure that generated code can find fields and variants by number r
|
|
|
73
73
|
Consider a simple k program:
|
|
74
74
|
|
|
75
75
|
```k-lang
|
|
76
|
-
|
|
77
|
-
neg =
|
|
76
|
+
bool = ?< {} true, {} false >;
|
|
77
|
+
neg = bool < /true | false, /false | true > bool;
|
|
78
78
|
```
|
|
79
79
|
|
|
80
80
|
1. **Parsing:**
|
|
81
|
-
The compiler recognizes
|
|
81
|
+
The compiler recognizes the relation definitions `bool` and `neg`.
|
|
82
82
|
|
|
83
83
|
2. **Type analysis:**
|
|
84
|
-
|
|
84
|
+
The compiler derives that both the input and output of `neg` conform to boolean variants.
|
|
85
85
|
|
|
86
86
|
3. **Internal representation:**
|
|
87
87
|
The compiler constructs an internal tree describing that
|
|
@@ -105,13 +105,13 @@ Before producing final code, many compilers use an *intermediate representation*
|
|
|
105
105
|
It is a language designed to be easy to generate and easy to translate further into real machine code.
|
|
106
106
|
For `k`, the IR mirrors the structure of partial functions:
|
|
107
107
|
|
|
108
|
-
| Concept in k
|
|
109
|
-
|
|
|
110
|
-
| Projection `.x` `/x`
|
|
111
|
-
| Composition `(f g)`
|
|
112
|
-
| Union `<f,g>`
|
|
113
|
-
| Product `{.x f, .y g}`
|
|
114
|
-
|
|
|
108
|
+
| Concept in k | IR operation |
|
|
109
|
+
| ----------------------- | -------------------------------- |
|
|
110
|
+
| Projection `.x` `/x` | `PROJECT label_id` |
|
|
111
|
+
| Composition `(f g)` | `CALL f; CALL g` |
|
|
112
|
+
| Union `<f,g>` | `TRY f; IF undefined THEN TRY g` |
|
|
113
|
+
| Product `{.x f, .y g}` | `PRODUCT_CALL (f, g); COMBINE` |
|
|
114
|
+
| Filter restriction `?F` | `CHECK_FILTER pattern_id` |
|
|
115
115
|
|
|
116
116
|
The compiler converts each AST node into one or more IR instructions.
|
|
117
117
|
The `PRODUCT_CALL(f, g)` instruction is a higher-level concept that implies applying both `f` and `g` to the same input value.
|
|
@@ -42,24 +42,23 @@ Each function in the program becomes a small list or tree of such IR instruction
|
|
|
42
42
|
Source program:
|
|
43
43
|
|
|
44
44
|
```k-lang
|
|
45
|
-
|
|
46
|
-
neg =
|
|
45
|
+
bool = ?< {} true, {} false >;
|
|
46
|
+
neg = ?< {} true, {} false > < /true | false, /false | true >;
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
The IR for `neg` can be written informally as:
|
|
50
50
|
|
|
51
51
|
```text
|
|
52
52
|
neg:
|
|
53
|
-
|
|
53
|
+
CHECK_FILTER bool
|
|
54
54
|
UNION [
|
|
55
55
|
SEQ [ PROJECT true, CONST false ],
|
|
56
56
|
SEQ [ PROJECT false, CONST true ]
|
|
57
57
|
]
|
|
58
|
-
TYPECHECK bool
|
|
59
58
|
```
|
|
60
59
|
|
|
61
60
|
This IR expresses the same logic as the source:
|
|
62
|
-
check the
|
|
61
|
+
check that the value matches the pattern, then try the first projection `/true`, otherwise the second.
|
|
63
62
|
|
|
64
63
|
---
|
|
65
64
|
|
|
@@ -89,8 +88,8 @@ The process of converting the AST to IR follows a recursive pattern:
|
|
|
89
88
|
2. **Compositions** `(f g h)` become a `SEQ` list of their components.
|
|
90
89
|
3. **Unions** `<f,g>` become a `UNION` list.
|
|
91
90
|
4. **Products** `{f l₁, g l₂}` become a `PRODUCT` list with labeled entries.
|
|
92
|
-
5. **
|
|
93
|
-
6.
|
|
91
|
+
5. **Filter expressions** `?F` become `CHECK_FILTER` or `TYPECHECK` instructions.
|
|
92
|
+
6. Inductive filters that match derived shapes can be elided or turned into no-op identity during execution.
|
|
94
93
|
|
|
95
94
|
Each transformation step produces IR nodes with fixed behavior and explicit order.
|
|
96
95
|
|
|
@@ -67,8 +67,8 @@ This rule allows the decoder to know, from the type alone, how many bits to read
|
|
|
67
67
|
|
|
68
68
|
For the type
|
|
69
69
|
|
|
70
|
-
```
|
|
71
|
-
|
|
70
|
+
```k-lang
|
|
71
|
+
bnat = ?< Bnat 0, Bnat 1, {} _ > = Bnat;
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
the canonical form has three transitions from state C0.
|