@fraczak/k 6.0.0 → 6.0.2
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/.codex +0 -0
- package/AGENTS.md +35 -0
- package/CHANGELOG.md +48 -0
- package/CLAUDE.md +64 -0
- package/DOCS/BIG_PICTURE.md +4 -8
- package/DOCS/BINARY_CODEC_STATUS_AND_TODO.md +74 -0
- package/DOCS/CONVERGENCE.md +92 -0
- package/DOCS/DIVERGENCE_DETECTION.md +24 -0
- package/DOCS/Makefile +99 -0
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +217 -0
- package/DOCS/PATTERNS.md +114 -0
- package/DOCS/PATTERNS_AND_TYPED_VALUES.md +665 -0
- package/DOCS/REPL.md +125 -125
- package/DOCS/TEXTUAL_VALUES.md +108 -0
- package/DOCS/TYPE_DERIVATION.md +230 -0
- package/DOCS/a.html +398 -0
- package/DOCS/book/06-values-in-memory.md +1085 -0
- package/DOCS/book/07-the-partial-function-abi.md +143 -0
- package/DOCS/book/08-operational-semantics-and-execution.md +201 -0
- package/DOCS/book/09-compiler-architecture.md +160 -0
- package/DOCS/book/10-from-ast-to-intermediate-representation.md +167 -0
- package/DOCS/book/14-canonical-serialization.md +176 -0
- package/DOCS/book/appendix-b-incorporating-external-predefined-types-and-functions.md +155 -0
- package/DOCS/book/overview.txt +68 -0
- package/NAT.k~ +452 -0
- package/README.md +71 -27
- package/codecs/BINARY_FORMAT.html +471 -0
- package/codecs/POLYMORPHIC_BINARY_FORMAT.html +355 -0
- package/codecs/README.md +8 -0
- package/codecs/pandoc.css +71 -0
- package/codecs/runtime/test-codec.mjs +89 -0
- package/ieee.klib +0 -0
- package/k-vscode/package-lock.json +4176 -0
- package/package.json +10 -13
- package/{codecs/k-pattern.mjs → patterns/from-k.mjs} +3 -3
- package/repl2.mjs +270 -51
- package/scripts/generate-dependency-graph.mjs +121 -0
- package/test-repl2.mjs +67 -9
- package/type_registry/registry.mjs~ +105 -0
- package/type_registry/typeParser.jison~ +132 -0
package/DOCS/REPL.md
CHANGED
|
@@ -1,189 +1,189 @@
|
|
|
1
1
|
# k Interpreter
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`repl2.mjs` is the interactive k interpreter. `k-repl` and `k-repl2` both
|
|
4
|
+
start it.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
its internal state: definitions accumulate incrementally, expressions compile
|
|
7
|
-
in the context of the current library state, and the session can be exported as
|
|
8
|
-
either a reusable `.klib` library or an executable `.ko` object.
|
|
6
|
+
The interpreter keeps a live `.klib`-style state in memory:
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
- registered codes
|
|
9
|
+
- compiled relations
|
|
10
|
+
- human aliases for both
|
|
11
|
+
- the current value flowing through the session
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
Raw k snippets compile on top of that state. You can also export the current
|
|
14
|
+
session as a `.klib` library or compile an executable `.ko` object from an
|
|
15
|
+
expression in the session context.
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
┌─────────────────────────────────────────────────┐
|
|
18
|
-
│ codes: { hash → code definition } │ ← registered types
|
|
19
|
-
│ rels: { @hash → typed relation } │ ← compiled relations
|
|
20
|
-
│ aliases: { name → @hash } │ ← human names
|
|
21
|
-
│ value: current value (with .pattern) │ ← last result
|
|
22
|
-
│ lastMain: last relation/expression │ ← default .ko main
|
|
23
|
-
└─────────────────────────────────────────────────┘
|
|
24
|
-
```
|
|
17
|
+
## Prompt Model
|
|
25
18
|
|
|
26
|
-
|
|
27
|
-
- `aliases` maps human names to canonical hashes. Redefining a name updates
|
|
28
|
-
the alias; the old definition remains in `rels` (content-addressed, no conflict).
|
|
29
|
-
- `value` is the current pipeline value, initially `{}`.
|
|
19
|
+
There are two kinds of input:
|
|
30
20
|
|
|
31
|
-
|
|
21
|
+
- commands, starting with `:`
|
|
22
|
+
- raw k source
|
|
23
|
+
|
|
24
|
+
Commands execute immediately, but only when there is no open raw snippet in the
|
|
25
|
+
buffer.
|
|
32
26
|
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
Raw k source is accumulated until the interpreter can decide the snippet is
|
|
28
|
+
complete.
|
|
35
29
|
|
|
36
|
-
|
|
37
|
-
commands such as `:load` and `:export`, and canonical names that start with
|
|
38
|
-
`@`.
|
|
30
|
+
## Commands
|
|
39
31
|
|
|
40
|
-
| Command |
|
|
41
|
-
|
|
42
|
-
| `:
|
|
43
|
-
| `:
|
|
32
|
+
| Command | Meaning |
|
|
33
|
+
| --- | --- |
|
|
34
|
+
| `:help` | Show command summary |
|
|
35
|
+
| `:type name = <...>` | Define a type alias |
|
|
36
|
+
| `:type name` | Show the canonical definition of a type |
|
|
37
|
+
| `:code name` | Alias for `:C name` |
|
|
38
|
+
| `:rel name = expr` | Define a relation alias |
|
|
44
39
|
| `:def name = expr` | Alias for `:rel` |
|
|
45
|
-
| `:run expr` |
|
|
46
|
-
| `:
|
|
47
|
-
| `:
|
|
48
|
-
| `:
|
|
40
|
+
| `:run expr` | Evaluate `expr` on the current value |
|
|
41
|
+
| `:eval expr` | Alias for `:run` |
|
|
42
|
+
| `:t name` | Show relation input/output filters |
|
|
43
|
+
| `:d name` | Show relation definition |
|
|
44
|
+
| `:C name` | Show canonical code definition |
|
|
49
45
|
| `:codes` | List type aliases |
|
|
50
46
|
| `:rels` | List relation aliases |
|
|
51
|
-
| `:
|
|
52
|
-
| `:klib file` | Export current state as `.klib` |
|
|
53
|
-
| `:ko file
|
|
54
|
-
| `:
|
|
55
|
-
| `:
|
|
56
|
-
| `:
|
|
57
|
-
| `:reset` | Clear all state |
|
|
58
|
-
| `:help` | Show available commands |
|
|
59
|
-
| `:quit` | Exit |
|
|
60
|
-
|
|
61
|
-
The `/` character is never treated as a command prefix, because it is part of
|
|
62
|
-
k expression syntax.
|
|
47
|
+
| `:load file` | Load `.k` source or `.klib` into the current state |
|
|
48
|
+
| `:klib file` | Export current state as a `.klib` library |
|
|
49
|
+
| `:ko file expr` | Export a `.ko` executable with `expr` as main |
|
|
50
|
+
| `:val` | Print current value and JSON form |
|
|
51
|
+
| `:reset` | Reset interpreter state |
|
|
52
|
+
| `:quit` / `:exit` | Exit |
|
|
63
53
|
|
|
64
|
-
##
|
|
54
|
+
## Raw Snippets
|
|
65
55
|
|
|
66
|
-
Raw
|
|
56
|
+
Raw input is compiled as k source on top of the current state.
|
|
67
57
|
|
|
68
|
-
|
|
69
|
-
- `name = expr;` is treated like `:rel name = expr`.
|
|
70
|
-
- Any other non-command input is treated like `:run expr`.
|
|
71
|
-
|
|
72
|
-
For command-based use, semicolons are optional in `:type` and `:rel`.
|
|
58
|
+
Examples:
|
|
73
59
|
|
|
74
|
-
|
|
60
|
+
```k
|
|
61
|
+
> {} |succ
|
|
62
|
+
```
|
|
75
63
|
|
|
76
|
-
|
|
64
|
+
```k
|
|
65
|
+
> $ bool = <{} true, {} false>;
|
|
66
|
+
```
|
|
77
67
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
68
|
+
```k
|
|
69
|
+
> $ bool = <{} true, {} false>
|
|
70
|
+
; not = $bool </true | false, {} | true >
|
|
71
|
+
; {} |true not
|
|
72
|
+
```
|
|
81
73
|
|
|
82
|
-
|
|
74
|
+
The interpreter uses these rules, in order:
|
|
83
75
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
-
|
|
76
|
+
1. If the line ends with `\` followed only by spaces, keep buffering.
|
|
77
|
+
2. If the line ends with `;` followed only by spaces, that line definitively
|
|
78
|
+
closes the snippet.
|
|
79
|
+
3. Otherwise, try to parse the buffered snippet:
|
|
80
|
+
- if it is a complete k program, compile it now
|
|
81
|
+
- if it is a valid prefix, wait for more input
|
|
82
|
+
- otherwise report the parse error immediately
|
|
89
83
|
|
|
90
|
-
|
|
84
|
+
After a snippet is accepted:
|
|
91
85
|
|
|
92
|
-
-
|
|
93
|
-
|
|
94
|
-
-
|
|
95
|
-
|
|
96
|
-
- Print result with envelope (see Output Format).
|
|
86
|
+
- if it has a terminal expression, compile it and evaluate it on the current
|
|
87
|
+
value
|
|
88
|
+
- if it is definitions only, compile it into the current state and print
|
|
89
|
+
nothing on success
|
|
97
90
|
|
|
98
|
-
|
|
91
|
+
This makes raw snippets useful both for interactive evaluation and for growing
|
|
92
|
+
the live library context.
|
|
99
93
|
|
|
100
|
-
|
|
101
|
-
human names resolve to library relations:
|
|
94
|
+
## State
|
|
102
95
|
|
|
103
|
-
|
|
104
|
-
add = @mKEA...; succ = @Swjz...; nat = @w8iS...;
|
|
105
|
-
<user input>
|
|
106
|
-
```
|
|
96
|
+
The interpreter keeps:
|
|
107
97
|
|
|
108
|
-
|
|
109
|
-
|
|
98
|
+
- `codes`: canonical code definitions
|
|
99
|
+
- `rels`: canonical compiled relations
|
|
100
|
+
- `typeAliases`: human type names to canonical hashes
|
|
101
|
+
- `relAliases`: human relation names to canonical hashes
|
|
102
|
+
- `value`: current value, initially `{}`
|
|
110
103
|
|
|
111
|
-
|
|
104
|
+
Definitions are content-addressed. Rebinding an alias changes the name-to-hash
|
|
105
|
+
mapping, but older canonical definitions remain available by hash.
|
|
112
106
|
|
|
113
|
-
##
|
|
107
|
+
## Alias Resolution
|
|
114
108
|
|
|
115
|
-
|
|
109
|
+
Before compiling user input, the interpreter injects an alias preamble so human
|
|
110
|
+
names can be reused naturally:
|
|
116
111
|
|
|
117
|
-
```
|
|
118
|
-
|
|
112
|
+
```k
|
|
113
|
+
$ nat = @...;
|
|
114
|
+
succ = @...;
|
|
115
|
+
<user snippet>
|
|
119
116
|
```
|
|
120
117
|
|
|
121
|
-
|
|
118
|
+
Type aliases use `$ name = @hash;`. Relation aliases use `name = @hash;`.
|
|
122
119
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
{succ: {succ: {zero: {}}}} ?<{} zero, X succ>=X
|
|
120
|
+
Diagnostic locations are remapped back to the visible user snippet, so error
|
|
121
|
+
line numbers do not count the hidden preamble.
|
|
126
122
|
|
|
127
|
-
|
|
128
|
-
{{{}|1 car, {}|nil cdr}|cons} ?<{} nil, {<{} 0, {} 1> car, X cdr} cons>=X
|
|
129
|
-
```
|
|
123
|
+
## Completion
|
|
130
124
|
|
|
131
|
-
|
|
132
|
-
`codecs/runtime/show-value.mjs`.
|
|
125
|
+
Tab completion covers:
|
|
133
126
|
|
|
134
|
-
|
|
127
|
+
- command names after `:`
|
|
128
|
+
- file paths for `:load`, `:klib`, and `:ko`
|
|
129
|
+
- type aliases
|
|
130
|
+
- relation aliases
|
|
131
|
+
- canonical names beginning with `@`
|
|
135
132
|
|
|
136
|
-
|
|
137
|
-
... undefined
|
|
138
|
-
```
|
|
133
|
+
Type aliases also complete in `$name` position inside raw k input.
|
|
139
134
|
|
|
140
|
-
## Loading
|
|
135
|
+
## Loading
|
|
141
136
|
|
|
142
137
|
### `:load file.k`
|
|
143
138
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
139
|
+
Compiles the source in the current library context, merges the resulting codes
|
|
140
|
+
and relations into the session, and recovers aliases from user-defined names in
|
|
141
|
+
the file.
|
|
147
142
|
|
|
148
143
|
### `:load file.klib`
|
|
149
144
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
- Update aliases from `meta` (recover source names from origins).
|
|
153
|
-
|
|
154
|
-
## Exporting
|
|
145
|
+
Decodes the library file and merges its codes, relations, and metadata into the
|
|
146
|
+
session.
|
|
155
147
|
|
|
156
|
-
|
|
148
|
+
## Export
|
|
157
149
|
|
|
158
|
-
|
|
159
|
-
- `meta` is built from the alias table (each alias → origin entry).
|
|
150
|
+
### `:klib file`
|
|
160
151
|
|
|
161
|
-
|
|
152
|
+
Writes the current interpreter state as a `.klib` library.
|
|
162
153
|
|
|
163
|
-
|
|
154
|
+
### `:ko file expr`
|
|
164
155
|
|
|
165
|
-
|
|
156
|
+
Compiles `expr` as the main expression in the current interpreter context and
|
|
157
|
+
writes the resulting executable `.ko` object.
|
|
166
158
|
|
|
167
|
-
|
|
168
|
-
- If `expr` is omitted, reuse the last relation definition or expression that
|
|
169
|
-
was evaluated in the interpreter.
|
|
170
|
-
- The current `.klib` state is passed as the compilation library context.
|
|
159
|
+
## Output
|
|
171
160
|
|
|
172
|
-
|
|
161
|
+
Evaluated values print in k syntax together with the inferred envelope:
|
|
173
162
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
163
|
+
```text
|
|
164
|
+
{succ: {succ: {zero: {}}}} ?<{} zero, X succ>=X
|
|
165
|
+
```
|
|
177
166
|
|
|
178
|
-
|
|
167
|
+
`undefined` prints as:
|
|
179
168
|
|
|
169
|
+
```text
|
|
170
|
+
... undefined
|
|
180
171
|
```
|
|
172
|
+
|
|
173
|
+
`valueToK`, `propertyListToFilter`, and `valueWithEnvelopeToK` from
|
|
174
|
+
`codecs/runtime/show-value.mjs` are used for rendering.
|
|
175
|
+
|
|
176
|
+
## Example Session
|
|
177
|
+
|
|
178
|
+
```text
|
|
181
179
|
> :type nat = <{} zero, nat succ>
|
|
182
180
|
$ nat = @...
|
|
183
181
|
> :rel succ = |succ
|
|
184
182
|
succ = @...
|
|
185
|
-
>
|
|
186
|
-
{}
|
|
183
|
+
> {} |zero
|
|
184
|
+
{zero: {}} ?<{} zero, X succ>=X
|
|
185
|
+
> :t succ
|
|
186
|
+
succ : ?X --> ?<{} zero, X succ>=X (@...)
|
|
187
187
|
> :klib nat.klib
|
|
188
188
|
saved nat.klib
|
|
189
189
|
> :ko succ.ko succ
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Textual k Values
|
|
2
|
+
|
|
3
|
+
`k-parse` and `k-print` work with a textual notation for k values.
|
|
4
|
+
|
|
5
|
+
It looks like JSON because products print as JSON objects, but semantically it
|
|
6
|
+
is not a generic JSON format. It is a readable notation for values built from
|
|
7
|
+
the two k data constructors:
|
|
8
|
+
|
|
9
|
+
- product
|
|
10
|
+
- tagged union
|
|
11
|
+
|
|
12
|
+
## The Value Model
|
|
13
|
+
|
|
14
|
+
A k value is a tree.
|
|
15
|
+
|
|
16
|
+
- A product is a mapping from field labels to child values.
|
|
17
|
+
- A union is a single chosen tag together with its payload value.
|
|
18
|
+
|
|
19
|
+
There are no primitive leaves. The base leaf is the empty product:
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
{}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Textual Notation
|
|
26
|
+
|
|
27
|
+
The textual notation used by `k-parse` and `k-print` is:
|
|
28
|
+
|
|
29
|
+
- `{}` for the empty product
|
|
30
|
+
- `{"field": value, ...}` for a product
|
|
31
|
+
- `{"tag": value}` for a union
|
|
32
|
+
|
|
33
|
+
The last form is why the notation only looks like JSON. Syntactically, a
|
|
34
|
+
single-entry object is ambiguous in plain JSON, but in k it is interpreted
|
|
35
|
+
through the inferred or supplied pattern.
|
|
36
|
+
|
|
37
|
+
Examples:
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
{}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
{"point":{"x":{},"y":{}}}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
{"succ":{"succ":{"zero":{}}}}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The last example is the k value usually written in native notation as:
|
|
52
|
+
|
|
53
|
+
```k
|
|
54
|
+
{}|zero|succ|succ
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Relation to Native k Notation
|
|
58
|
+
|
|
59
|
+
The native k notation is more explicit for interactive work:
|
|
60
|
+
|
|
61
|
+
- product construction: `{ v field, w other }`
|
|
62
|
+
- union introduction: `v |tag`
|
|
63
|
+
|
|
64
|
+
`k-print` does not emit that native notation. It emits the JSON-like tree
|
|
65
|
+
notation because it is easy to pipe, inspect, and round-trip through standard
|
|
66
|
+
text tooling.
|
|
67
|
+
|
|
68
|
+
## `k-parse`
|
|
69
|
+
|
|
70
|
+
`k-parse`:
|
|
71
|
+
|
|
72
|
+
1. reads textual k values
|
|
73
|
+
2. optionally takes an input type or input pattern
|
|
74
|
+
3. produces the binary `pattern + value` stream
|
|
75
|
+
|
|
76
|
+
When no explicit pattern or type is supplied, `k-parse` derives a witness
|
|
77
|
+
pattern from the textual tree.
|
|
78
|
+
|
|
79
|
+
## `k-print`
|
|
80
|
+
|
|
81
|
+
`k-print`:
|
|
82
|
+
|
|
83
|
+
1. reads the binary `pattern + value` stream
|
|
84
|
+
2. decodes it to a runtime value with its carried pattern
|
|
85
|
+
3. prints the value tree in JSON-like notation
|
|
86
|
+
|
|
87
|
+
So `k-print` is not a JSON decoder in the general sense. It is a renderer from
|
|
88
|
+
k runtime values to a JSON-shaped textual notation.
|
|
89
|
+
|
|
90
|
+
## Ambiguity and Patterns
|
|
91
|
+
|
|
92
|
+
The textual tree alone does not always determine whether a single-child node is
|
|
93
|
+
meant as a union or a singleton product. That is why patterns matter.
|
|
94
|
+
|
|
95
|
+
When `k-parse` has no explicit input pattern, it applies the current witness
|
|
96
|
+
rule:
|
|
97
|
+
|
|
98
|
+
- empty node => closed product
|
|
99
|
+
- node with multiple children => closed product
|
|
100
|
+
- node with one child => open union by default
|
|
101
|
+
|
|
102
|
+
An explicit input pattern or input type can force a different interpretation.
|
|
103
|
+
|
|
104
|
+
## See Also
|
|
105
|
+
|
|
106
|
+
- [codecs/README.md](../codecs/README.md)
|
|
107
|
+
- [DOCS/PATTERNS.md](./PATTERNS.md)
|
|
108
|
+
- [DOCS/OBJECT_FILE_AND_PATTERN.md](./OBJECT_FILE_AND_PATTERN.md)
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# Type Derivation Algorithm
|
|
2
|
+
|
|
3
|
+
## 1. Overview
|
|
4
|
+
|
|
5
|
+
This algorithm infers type constraints for programs consisting of mutually recursive partial functions over algebraic data types (products and unions).
|
|
6
|
+
|
|
7
|
+
**Input:** AST of a `k` program, consisting of function definitions (expressions) - can be seen as a set of (recursive) equations.
|
|
8
|
+
**Output:** Annotated AST with type patterns (also called filters)
|
|
9
|
+
|
|
10
|
+
It is assumed that we have access (through APIs) to a universal "type registry", which provides us with unique (canonical) names for each type.
|
|
11
|
+
|
|
12
|
+
## 2. Patterns
|
|
13
|
+
|
|
14
|
+
A **pattern** represents a set of types:
|
|
15
|
+
|
|
16
|
+
| Notation | Meaning | Fields |
|
|
17
|
+
|----------|---------|--------|
|
|
18
|
+
| `(...)` | Open unknown | Any |
|
|
19
|
+
| `{...}` | Open product | At least specified |
|
|
20
|
+
| `<...>` | Open union | At least specified |
|
|
21
|
+
| `{}` | Closed product | Exactly specified |
|
|
22
|
+
| `<>` | Closed union | Exactly specified |
|
|
23
|
+
| `T` | Named type | From type definition |
|
|
24
|
+
|
|
25
|
+
**Fields:** Each pattern has associated field labels. For open patterns, additional fields may exist. For closed patterns, the field set is exact.
|
|
26
|
+
Unknown-kind patterns have only the open form `(...)`; a closed filter must choose product `{...}`/`{}` or union `<...>`/`<>`.
|
|
27
|
+
|
|
28
|
+
A type pattern is a singleton pattern, i.e., only one type is captured by such a pattern.
|
|
29
|
+
|
|
30
|
+
## 3. Pattern Graph - a data structure used during type derivation
|
|
31
|
+
|
|
32
|
+
**Nodes:** Patterns organized in a "reps" (representatives) forest, similar to union-find. However, a union of two (or more) different trees always produces a new "rep" (root) node, joining the trees.
|
|
33
|
+
**Edges:** Labeled by field names, pointing to other patterns
|
|
34
|
+
**Representatives:** Root nodes (called reps) represent equivalence classes
|
|
35
|
+
|
|
36
|
+
**Operations:**
|
|
37
|
+
|
|
38
|
+
- `find(p)` - get representative of pattern `p`
|
|
39
|
+
- `unify(p₁, ..., pₙ)` - merge patterns into equivalence class, potentially adding a new rep (root); the rep gathers all edges of their children
|
|
40
|
+
- `clone(p₁, ..., pₙ)` - generate a copy of the pattern graph connected to the patterns
|
|
41
|
+
- `compact()` - discovers all singleton patterns and replaces them by "Named types"
|
|
42
|
+
|
|
43
|
+
## 4. Unification
|
|
44
|
+
|
|
45
|
+
`unify(p₁, ..., pₙ)` computes the least upper bound (most specific common pattern); it may add a new node (rep) into the reps forest; the operation does not modify any existing pattern node
|
|
46
|
+
|
|
47
|
+
**Rules:**
|
|
48
|
+
|
|
49
|
+
- **Open + Open:** Merge field sets, stay open
|
|
50
|
+
- **Open + Closed:** Check fields ⊆, become closed
|
|
51
|
+
- **Closed + Closed:** Check fields =, stay closed
|
|
52
|
+
- **Product ⊥ Union:** Error (incompatible)
|
|
53
|
+
- **Type T:** Unique (canonical name)
|
|
54
|
+
|
|
55
|
+
**Algorithm:**
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
1. Find representatives of all patterns
|
|
59
|
+
2. If the set of reps is a singleton, return it as the result
|
|
60
|
+
3. Compute merged pattern descriptor
|
|
61
|
+
4. Create new representative node
|
|
62
|
+
5. Migrate edges from old representatives
|
|
63
|
+
6. Recursively unify edge destinations for each field name
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 5. Local Typing Rules
|
|
67
|
+
|
|
68
|
+
For each expression type, define input/output pattern constraints:
|
|
69
|
+
|
|
70
|
+
### Composition `(e₁ e₂ ... eₙ)`
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
in((e₁ e₂ ... eₙ)) = in(e₁)
|
|
74
|
+
out(eᵢ) = in(eᵢ₊₁) for i = 1..n-1
|
|
75
|
+
out((e₁ e₂ ... eₙ)) = out(eₙ)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
In case when `n=0`, identity, `()`
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
in(()) = out(())
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Product `{e₁ l₁, ..., eₙ lₙ}`
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
in(e₁) = ... = in(eₙ) = in({e₁ l₁, ..., eₙ lₙ})
|
|
88
|
+
out({e₁ l₁, ..., eₙ lₙ}) = {} with edges lᵢ → out(eᵢ)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Variant constructor `|l`
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
out(|l) = <...> with edge l → in(|l)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Union `<e₁, ..., eₙ>`
|
|
98
|
+
|
|
99
|
+
```text
|
|
100
|
+
in(e₁) = ... = in(eₙ) = in(<e₁, ..., eₙ>)
|
|
101
|
+
out(e₁) = ... = out(eₙ) = out(<e₁, ..., eₙ>)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Projection
|
|
105
|
+
|
|
106
|
+
#### Dot `.l`
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
in(.l) = {...} with edge l → out(.l)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
#### Div `/t`
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
in(/t) = <...> with edge t → out(/t)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Function reference `f`
|
|
119
|
+
|
|
120
|
+
```text
|
|
121
|
+
in(f) = LOOKUP(in(f))
|
|
122
|
+
out(f) = LOOKUP(out(f))
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Once the type derivation for the defining expression for `f` is done, the input and output patterns are stored and will be used.
|
|
126
|
+
|
|
127
|
+
### Type `$ T`
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
in(T) = out(T) = pattern(T)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Filter `? F`
|
|
134
|
+
|
|
135
|
+
```text
|
|
136
|
+
see patterns.filterToPattern(F)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Filter expression is a syntax for describing pattern graphs.
|
|
140
|
+
|
|
141
|
+
## 6. Global Algorithm
|
|
142
|
+
|
|
143
|
+
### Phase 1: Initialization
|
|
144
|
+
|
|
145
|
+
```text
|
|
146
|
+
For each function definition:
|
|
147
|
+
1. Create empty pattern graph
|
|
148
|
+
2. Traverse expression AST
|
|
149
|
+
3. Create [input, output] pattern pair per node of the AST
|
|
150
|
+
4. Apply local typing rules
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Phase 2: Dependency Analysis
|
|
154
|
+
|
|
155
|
+
```text
|
|
156
|
+
1. Build dependency graph (function → referenced functions)
|
|
157
|
+
2. Compute strongly connected components (SCCs)
|
|
158
|
+
3. Topologically sort SCCs (bottom-up)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Phase 3: Fixed-Point Iteration
|
|
162
|
+
|
|
163
|
+
```text
|
|
164
|
+
For each SCC (in topological order):
|
|
165
|
+
Repeat until convergence (max 10 iterations):
|
|
166
|
+
For each function `f` in SCC:
|
|
167
|
+
1. Compact `f`'s pattern graph
|
|
168
|
+
2. For each occurrence `o` of `g` in `f`, clone(in(g), out(g)) and unify input and output patterns of `o` with the corresponding cloned patterns
|
|
169
|
+
|
|
170
|
+
If pattern graphs unchanged: break
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## 7. Compaction
|
|
174
|
+
|
|
175
|
+
**Purpose:** Replace all pattern nodes by their reps and replace all singleton patterns by types.
|
|
176
|
+
|
|
177
|
+
**Algorithm:**
|
|
178
|
+
|
|
179
|
+
```text
|
|
180
|
+
1. Build a new graph only on reps (keep the mappings from pattern node to its rep)
|
|
181
|
+
2. Identify singleton patterns (closed patterns with no open ancestors)
|
|
182
|
+
3. Register singletons as named types and use them as type pattern nodes
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## 8. Convergence
|
|
186
|
+
|
|
187
|
+
**Criterion:** Pattern graph structure unchanged between iterations
|
|
188
|
+
|
|
189
|
+
**Measured by:**
|
|
190
|
+
1. Representative forest structure (parent pointers)
|
|
191
|
+
2. Edge sets for each representative
|
|
192
|
+
3. Pattern descriptors for each representative
|
|
193
|
+
|
|
194
|
+
**Algorithm:**
|
|
195
|
+
```text
|
|
196
|
+
For each function f in SCC:
|
|
197
|
+
1. Serialize reps forest: {nodeId → parentId}
|
|
198
|
+
2. Serialize edge structure: {repId → {label → [targetReps]}}
|
|
199
|
+
3. Serialize pattern info: {repId → {pattern, fields, type}}
|
|
200
|
+
4. Combine into canonical form
|
|
201
|
+
|
|
202
|
+
Converged = (current_state == previous_state)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Guarantee:** Monotonic refinement + iteration bound ensures termination
|
|
206
|
+
|
|
207
|
+
## 9. Error Handling
|
|
208
|
+
|
|
209
|
+
**Unification errors:**
|
|
210
|
+
|
|
211
|
+
- Product vs Union
|
|
212
|
+
- Closed pattern field mismatch
|
|
213
|
+
- Two distinct type patterns (types with different canonical names) are always incompatible
|
|
214
|
+
|
|
215
|
+
**Other errors:**
|
|
216
|
+
|
|
217
|
+
- Undefined function reference
|
|
218
|
+
- Iteration limit exceeded
|
|
219
|
+
|
|
220
|
+
**Error reporting should include:**
|
|
221
|
+
|
|
222
|
+
- Source location
|
|
223
|
+
- Expression type
|
|
224
|
+
- Conflicting patterns
|
|
225
|
+
- Unification trace
|
|
226
|
+
|
|
227
|
+
## 10. Implementation Notes
|
|
228
|
+
|
|
229
|
+
- Use reps forest for performing and tracing unification
|
|
230
|
+
- Compact only at the end of an iteration to keep unification reasons for error messages
|