@fraczak/k 6.0.1 → 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.
Files changed (38) hide show
  1. package/AGENTS.md +35 -0
  2. package/CHANGELOG.md +48 -0
  3. package/CLAUDE.md +64 -0
  4. package/DOCS/BIG_PICTURE.md +4 -8
  5. package/DOCS/BINARY_CODEC_STATUS_AND_TODO.md +74 -0
  6. package/DOCS/CONVERGENCE.md +92 -0
  7. package/DOCS/DIVERGENCE_DETECTION.md +24 -0
  8. package/DOCS/Makefile +99 -0
  9. package/DOCS/OBJECT_FILE_AND_PATTERN.md +217 -0
  10. package/DOCS/PATTERNS.md +114 -0
  11. package/DOCS/PATTERNS_AND_TYPED_VALUES.md +665 -0
  12. package/DOCS/REPL.md +125 -125
  13. package/DOCS/TEXTUAL_VALUES.md +108 -0
  14. package/DOCS/TYPE_DERIVATION.md +230 -0
  15. package/DOCS/book/06-values-in-memory.md +1085 -0
  16. package/DOCS/book/07-the-partial-function-abi.md +143 -0
  17. package/DOCS/book/08-operational-semantics-and-execution.md +201 -0
  18. package/DOCS/book/09-compiler-architecture.md +160 -0
  19. package/DOCS/book/10-from-ast-to-intermediate-representation.md +167 -0
  20. package/DOCS/book/14-canonical-serialization.md +176 -0
  21. package/DOCS/book/appendix-b-incorporating-external-predefined-types-and-functions.md +155 -0
  22. package/DOCS/book/overview.txt +68 -0
  23. package/README.md +71 -27
  24. package/codecs/README.md +8 -0
  25. package/codecs/pandoc.css +71 -0
  26. package/codecs/runtime/test-codec.mjs +89 -0
  27. package/package.json +2 -2
  28. package/{codecs/k-pattern.mjs → patterns/from-k.mjs} +3 -3
  29. package/repl2.mjs +259 -50
  30. package/scripts/generate-dependency-graph.mjs +121 -0
  31. package/test-repl2.mjs +55 -8
  32. package/DOCS/book-combined.html +0 -3798
  33. package/DOCS/book-combined.md +0 -3745
  34. package/DOCS/book-combined.pdf +0 -0
  35. package/DOCS/book-combined.tex +0 -5682
  36. package/DOCS/book.html +0 -65
  37. package/DOCS/book.pdf +0 -0
  38. package/DOCS/book.tex +0 -150
package/DOCS/REPL.md CHANGED
@@ -1,189 +1,189 @@
1
1
  # k Interpreter
2
2
 
3
- ## Overview
3
+ `repl2.mjs` is the interactive k interpreter. `k-repl` and `k-repl2` both
4
+ start it.
4
5
 
5
- `repl2.mjs` is the interactive k interpreter. It uses the `.klib` format as
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
- `k-repl` and `k-repl2` both start this interpreter. The primary interface is
11
- command-based: commands start with `:`, and raw k input remains available as a
12
- short form for quick interactive work.
8
+ - registered codes
9
+ - compiled relations
10
+ - human aliases for both
11
+ - the current value flowing through the session
13
12
 
14
- ## State Model
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
- - `codes` and `rels` are the live .klib content.
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
- ## Commands
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
- Each line is a command. Multiline commands can be continued with a trailing
34
- `\`.
27
+ Raw k source is accumulated until the interpreter can decide the snippet is
28
+ complete.
35
29
 
36
- Tab completion is available for command names, file paths in file-taking
37
- commands such as `:load` and `:export`, and canonical names that start with
38
- `@`.
30
+ ## Commands
39
31
 
40
- | Command | Description |
41
- |---------|-------------|
42
- | `:type name = <...>` | Define a type |
43
- | `:rel name = expr` | Define a relation |
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` | Run an expression on the current value |
46
- | `:t name` | Show type signature of a relation |
47
- | `:d name` | Show definition of a relation |
48
- | `:type name` | Show definition of a type |
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
- | `:save file` | Save current state as `.klib` |
52
- | `:klib file` | Export current state as `.klib` |
53
- | `:ko file [expr]` | Export executable `.ko`; uses `expr` or the last relation/expression as main |
54
- | `:export file [expr]` | Export by extension: `.klib` or `.ko` |
55
- | `:load file` | Load `.k` source or `.klib` into state |
56
- | `:val` | Print current value with full detail |
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
- ## Shorthand Input
54
+ ## Raw Snippets
65
55
 
66
- Raw k input is still accepted:
56
+ Raw input is compiled as k source on top of the current state.
67
57
 
68
- - `$ name = <...>;` is treated like `:type name = <...>`.
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
- ## Input Handling
60
+ ```k
61
+ > {} |succ
62
+ ```
75
63
 
76
- ### Type Definition: `:type name = <...>`
64
+ ```k
65
+ > $ bool = <{} true, {} false>;
66
+ ```
77
67
 
78
- - Parse and register the code via `codes.register`.
79
- - Store canonical hash in `aliases[name]`.
80
- - Print: `$ name = @hash`
68
+ ```k
69
+ > $ bool = <{} true, {} false>
70
+ ; not = $bool </true | false, {} | true >
71
+ ; {} |true not
72
+ ```
81
73
 
82
- ### Relation Definition: `:rel name = expr`
74
+ The interpreter uses these rules, in order:
83
75
 
84
- - Build source: alias preamble + definition + `name` as main expression.
85
- - Compile with current `{codes, rels}` as library context.
86
- - Store compiled rel in `rels[@hash]`.
87
- - Update `aliases[name] → @hash`.
88
- - Print: `name = @hash`
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
- ### Expression Evaluation: `:run expr`
84
+ After a snippet is accepted:
91
85
 
92
- - Build source: alias preamble + expression as main.
93
- - Compile with current library context.
94
- - Run on current `value`.
95
- - Update `value` with result.
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
- ## Alias Preamble
91
+ This makes raw snippets useful both for interactive evaluation and for growing
92
+ the live library context.
99
93
 
100
- Before compiling any user input, the REPL prepends alias definitions so that
101
- human names resolve to library relations:
94
+ ## State
102
95
 
103
- ```k
104
- add = @mKEA...; succ = @Swjz...; nat = @w8iS...;
105
- <user input>
106
- ```
96
+ The interpreter keeps:
107
97
 
108
- For type aliases, the preamble uses `$ name = @hash;` syntax (referencing
109
- an existing canonical code by hash).
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
- This reuses the existing parser and compiler without modification.
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
- ## Output Format
107
+ ## Alias Resolution
114
108
 
115
- Values are printed as:
109
+ Before compiling user input, the interpreter injects an alias preamble so human
110
+ names can be reused naturally:
116
111
 
117
- ```
118
- <value-in-k-syntax> ?<pattern-as-filter>
112
+ ```k
113
+ $ nat = @...;
114
+ succ = @...;
115
+ <user snippet>
119
116
  ```
120
117
 
121
- Examples:
118
+ Type aliases use `$ name = @hash;`. Relation aliases use `name = @hash;`.
122
119
 
123
- ```
124
- > {}|zero|succ|succ
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
- > {{}|1 car, {}|nil cdr}|cons
128
- {{{}|1 car, {}|nil cdr}|cons} ?<{} nil, {<{} 0, {} 1> car, X cdr} cons>=X
129
- ```
123
+ ## Completion
130
124
 
131
- Uses `valueToK` and `propertyListToFilter` from
132
- `codecs/runtime/show-value.mjs`.
125
+ Tab completion covers:
133
126
 
134
- When the result is `undefined`, print:
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 Files
135
+ ## Loading
141
136
 
142
137
  ### `:load file.k`
143
138
 
144
- - Parse and compile the source as a library in the current context.
145
- - Merge resulting codes and rels into state.
146
- - Update aliases from `relAlias` (source name → hash).
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
- - Decode the .klib file.
151
- - Merge codes and rels into state.
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
- ### `:save file.klib`
148
+ ## Export
157
149
 
158
- - Serialize current `{codes, rels, meta, main: null}` as a .klib.
159
- - `meta` is built from the alias table (each alias → origin entry).
150
+ ### `:klib file`
160
151
 
161
- ### `:klib file.klib`
152
+ Writes the current interpreter state as a `.klib` library.
162
153
 
163
- - Alias for saving the current state as a `.klib`.
154
+ ### `:ko file expr`
164
155
 
165
- ### `:ko file.ko [expr]`
156
+ Compiles `expr` as the main expression in the current interpreter context and
157
+ writes the resulting executable `.ko` object.
166
158
 
167
- - Compile `expr` as the executable object's main expression.
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
- ### `:export file [expr]`
161
+ Evaluated values print in k syntax together with the inferred envelope:
173
162
 
174
- - If `file` ends in `.klib`, save the current library state.
175
- - If `file` ends in `.ko`, compile an executable object using `expr` or the
176
- last main expression.
163
+ ```text
164
+ {succ: {succ: {zero: {}}}} ?<{} zero, X succ>=X
165
+ ```
177
166
 
178
- ## Example
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
- > :run succ
186
- {}|succ ?<{} succ, ...>
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