@fraczak/k 5.1.1 → 6.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/Code-derivation-tests/blowup.mjs +3 -3
- package/Code-derivation-tests/bnat.mjs +2 -2
- package/Code-derivation-tests/codec-witness-pattern.mjs +50 -0
- package/Code-derivation-tests/convergence-strategy.mjs +24 -0
- package/Code-derivation-tests/dot.mjs +12 -9
- package/Code-derivation-tests/filter-syntax.mjs +21 -0
- package/Code-derivation-tests/loop.mjs +8 -2
- package/Code-derivation-tests/nat.mjs +1 -1
- package/Code-derivation-tests/not-not.mjs +3 -3
- package/Code-derivation-tests/pattern-envelope.mjs +68 -0
- package/Code-derivation-tests/rlz.mjs +2 -2
- package/{BIG_PICTURE.md → DOCS/BIG_PICTURE.md} +103 -50
- package/DOCS/REPL.md +191 -0
- package/DOCS/book/01-introduction.md +51 -0
- package/DOCS/book/02-syntax-and-values.md +111 -0
- package/DOCS/book/03-types-as-finite-automata.md +156 -0
- package/DOCS/book/04-partial-functions-and-composition.md +146 -0
- package/DOCS/book/05-typing-filters-and-normalization.md +111 -0
- package/DOCS/book.md +54 -0
- package/README.md +204 -508
- package/TypeGraph.mjs +43 -0
- package/TypePatternGraph.mjs +251 -0
- package/Value.mjs +192 -0
- package/augmentation.mjs +198 -0
- package/codecs/BINARY_FORMAT.md +53 -0
- package/codecs/POLYMORPHIC_BINARY_FORMAT.md +303 -0
- package/codecs/README.md +215 -0
- package/codecs/example-pipeline.mjs +149 -0
- package/codecs/ieee.mjs +140 -0
- package/codecs/int.mjs +104 -0
- package/codecs/json-codec.mjs +215 -0
- package/codecs/json.mjs +40 -0
- package/codecs/k-parse.mjs +90 -0
- package/codecs/k-pattern.mjs +75 -0
- package/codecs/k-print.mjs +46 -0
- package/codecs/runtime/codec.mjs +768 -0
- package/codecs/runtime/ieee-pattern.mjs +30 -0
- package/codecs/runtime/pattern-json.mjs +96 -0
- package/codecs/runtime/prefix-codec.mjs +425 -0
- package/codecs/runtime/show-value.mjs +68 -0
- package/codecs/runtime/typeFromValue.mjs +34 -0
- package/codecs/runtime/unicode-string.mjs +220 -0
- package/codecs/show.mjs +41 -0
- package/codecs/string-codec.mjs +80 -0
- package/codecs/unit.mjs +51 -0
- package/codecs/utf16.mjs +66 -0
- package/codecs/utf8.mjs +37 -0
- package/codes.mjs +146 -44
- package/compiler.mjs +111 -0
- package/convergence.mjs +197 -0
- package/core.k +197 -0
- package/export.mjs +22 -32
- package/hash.mjs +29 -31
- package/index.mjs +41 -15
- package/k-vscode/.vscode/launch.json +14 -0
- package/k-vscode/README.md +65 -0
- package/k-vscode/language-configuration.json +42 -0
- package/k-vscode/package.json +57 -0
- package/k-vscode/snippets/k.json +92 -0
- package/k-vscode/syntaxes/k.tmLanguage.json +243 -0
- package/k.mjs +56 -54
- package/object.mjs +517 -0
- package/objects/README.md +38 -0
- package/objects/compile-lib.mjs +42 -0
- package/objects/compile.mjs +42 -0
- package/objects/decompile.mjs +32 -0
- package/package.json +18 -8
- package/parser.jison +27 -46
- package/parser.mjs +68 -100
- package/pretty.mjs +21 -40
- package/repl2.mjs +652 -0
- package/run.mjs +264 -231
- package/symbol-table.mjs +3 -17
- package/test-fingerprint.mjs +7 -7
- package/test-hash-fuzz.mjs +107 -0
- package/test-hash-normalization.mjs +134 -0
- package/test-k-object.mjs +74 -0
- package/test-repl2.mjs +95 -0
- package/test.mjs +45 -70
- package/tests.sh +10 -1
- package/typing.mjs +129 -676
- package/unification.mjs +157 -0
- package/valueIO.mjs +54 -0
- package/valueParser.jison +143 -0
- package/valueParser.mjs +713 -0
- package/Code-derivation-tests/built-in.mjs +0 -19
- package/Code-derivation-tests/vector.mjs +0 -19
- package/Filters/bug.k +0 -3
- package/Filters/composing.k +0 -15
- package/Filters/filter.k +0 -9
- package/TODO.md +0 -53
- package/TYPING.md +0 -365
- package/k-repl.cast +0 -1913
- package/k.cast +0 -618
- package/my-objects.json +0 -6
- package/patterns.mjs +0 -543
- package/repl.mjs +0 -213
- package/test-filters.mjs +0 -45
- package/typing-test.mjs +0 -40
package/DOCS/REPL.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# k Interpreter
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
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.
|
|
9
|
+
|
|
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.
|
|
13
|
+
|
|
14
|
+
## State Model
|
|
15
|
+
|
|
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
|
+
```
|
|
25
|
+
|
|
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 `{}`.
|
|
30
|
+
|
|
31
|
+
## Commands
|
|
32
|
+
|
|
33
|
+
Each line is a command. Multiline commands can be continued with a trailing
|
|
34
|
+
`\`.
|
|
35
|
+
|
|
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
|
+
`@`.
|
|
39
|
+
|
|
40
|
+
| Command | Description |
|
|
41
|
+
|---------|-------------|
|
|
42
|
+
| `:type name = <...>` | Define a type |
|
|
43
|
+
| `:rel name = expr` | Define a relation |
|
|
44
|
+
| `: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 |
|
|
49
|
+
| `:codes` | List type aliases |
|
|
50
|
+
| `: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.
|
|
63
|
+
|
|
64
|
+
## Shorthand Input
|
|
65
|
+
|
|
66
|
+
Raw k input is still accepted:
|
|
67
|
+
|
|
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`.
|
|
73
|
+
|
|
74
|
+
## Input Handling
|
|
75
|
+
|
|
76
|
+
### Type Definition: `:type name = <...>`
|
|
77
|
+
|
|
78
|
+
- Parse and register the code via `codes.register`.
|
|
79
|
+
- Store canonical hash in `aliases[name]`.
|
|
80
|
+
- Print: `$ name = @hash`
|
|
81
|
+
|
|
82
|
+
### Relation Definition: `:rel name = expr`
|
|
83
|
+
|
|
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`
|
|
89
|
+
|
|
90
|
+
### Expression Evaluation: `:run expr`
|
|
91
|
+
|
|
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).
|
|
97
|
+
|
|
98
|
+
## Alias Preamble
|
|
99
|
+
|
|
100
|
+
Before compiling any user input, the REPL prepends alias definitions so that
|
|
101
|
+
human names resolve to library relations:
|
|
102
|
+
|
|
103
|
+
```k
|
|
104
|
+
add = @mKEA...; succ = @Swjz...; nat = @w8iS...;
|
|
105
|
+
<user input>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
For type aliases, the preamble uses `$ name = @hash;` syntax (referencing
|
|
109
|
+
an existing canonical code by hash).
|
|
110
|
+
|
|
111
|
+
This reuses the existing parser and compiler without modification.
|
|
112
|
+
|
|
113
|
+
## Output Format
|
|
114
|
+
|
|
115
|
+
Values are printed as:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
<value-in-k-syntax> ?<pattern-as-filter>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Examples:
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
> {}|zero|succ|succ
|
|
125
|
+
{succ: {succ: {zero: {}}}} ?<{} zero, X succ>=X
|
|
126
|
+
|
|
127
|
+
> {{}|1 car, {}|nil cdr}|cons
|
|
128
|
+
{{{}|1 car, {}|nil cdr}|cons} ?<{} nil, {<{} 0, {} 1> car, X cdr} cons>=X
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Uses `valueToK` and `propertyListToFilter` from
|
|
132
|
+
`codecs/runtime/show-value.mjs`.
|
|
133
|
+
|
|
134
|
+
When the result is `undefined`, print:
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
... undefined
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Loading Files
|
|
141
|
+
|
|
142
|
+
### `:load file.k`
|
|
143
|
+
|
|
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).
|
|
147
|
+
|
|
148
|
+
### `:load file.klib`
|
|
149
|
+
|
|
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
|
|
155
|
+
|
|
156
|
+
### `:save file.klib`
|
|
157
|
+
|
|
158
|
+
- Serialize current `{codes, rels, meta, main: null}` as a .klib.
|
|
159
|
+
- `meta` is built from the alias table (each alias → origin entry).
|
|
160
|
+
|
|
161
|
+
### `:klib file.klib`
|
|
162
|
+
|
|
163
|
+
- Alias for saving the current state as a `.klib`.
|
|
164
|
+
|
|
165
|
+
### `:ko file.ko [expr]`
|
|
166
|
+
|
|
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.
|
|
171
|
+
|
|
172
|
+
### `:export file [expr]`
|
|
173
|
+
|
|
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.
|
|
177
|
+
|
|
178
|
+
## Example
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
> :type nat = <{} zero, nat succ>
|
|
182
|
+
$ nat = @...
|
|
183
|
+
> :rel succ = |succ
|
|
184
|
+
succ = @...
|
|
185
|
+
> :run succ
|
|
186
|
+
{}|succ ?<{} succ, ...>
|
|
187
|
+
> :klib nat.klib
|
|
188
|
+
saved nat.klib
|
|
189
|
+
> :ko succ.ko succ
|
|
190
|
+
saved succ.ko (succ)
|
|
191
|
+
```
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Chapter 1 — Introduction
|
|
2
|
+
|
|
3
|
+
## **1.1 The purpose of this book**
|
|
4
|
+
|
|
5
|
+
This book describes a small programming language called **k**.
|
|
6
|
+
It is meant to show how data can be represented and transformed in a uniform, precise way.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## **1.2 Data as trees**
|
|
11
|
+
|
|
12
|
+
All information in `k` is treated as a **tree**.
|
|
13
|
+
A tree has:
|
|
14
|
+
|
|
15
|
+
* a single root,
|
|
16
|
+
* labeled edges (field names or tags),
|
|
17
|
+
* and possibly subtrees.
|
|
18
|
+
|
|
19
|
+
Both JSON objects and XML documents are trees in this sense.
|
|
20
|
+
Every `k` value is such a finite labeled tree.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## **1.3 Functions that may fail**
|
|
25
|
+
|
|
26
|
+
In ordinary mathematics a function always returns a result.
|
|
27
|
+
In `k`, a function may be **undefined** for some inputs.
|
|
28
|
+
For example, asking for the field `age` in a record that has no `age` is undefined.
|
|
29
|
+
|
|
30
|
+
We call such mappings **partial functions**.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## **1.4 Simplicity over features**
|
|
35
|
+
|
|
36
|
+
`k` avoids most language constructs: no *variables* and no *control statements*.
|
|
37
|
+
It has only:
|
|
38
|
+
|
|
39
|
+
1. **types** (which describe tree shapes), and
|
|
40
|
+
2. **partial functions** (which transform one tree into another).
|
|
41
|
+
|
|
42
|
+
These two ingredients are sufficient and powerful enough to express structured
|
|
43
|
+
computation in a concise and understandable way.
|
|
44
|
+
|
|
45
|
+
There is another concept in the language, called **filters**.
|
|
46
|
+
Filters play a role in the process of reasoning about types of partial functions.
|
|
47
|
+
Filters have been added to the syntax of the language as they allow explicit annotations
|
|
48
|
+
of "polymorphic" expressions, i.e., expressions which make sense in different contexts.
|
|
49
|
+
Filters are similar to *type classes* in other languages.
|
|
50
|
+
|
|
51
|
+
---
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Chapter 2 — Syntax and Values
|
|
2
|
+
|
|
3
|
+
## **2.1 Language fragments**
|
|
4
|
+
|
|
5
|
+
The `k` language has only one kind of program element: a **definition**.
|
|
6
|
+
A program is a sequence of definitions of two kinds:
|
|
7
|
+
|
|
8
|
+
```k-lang
|
|
9
|
+
$ type_name = ...type_expression... ;
|
|
10
|
+
function_name = ...expression... ;
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The definitions are followed in the file by the *main expression*; it represents the partial function defined by the program as a whole.
|
|
14
|
+
|
|
15
|
+
There is no syntax for values.
|
|
16
|
+
Every syntactic form in an expression describes a **function** -- possibly a constant function that always returns the same value.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## **2.2 Types**
|
|
21
|
+
|
|
22
|
+
A type describes the possible **tree shapes** of values.
|
|
23
|
+
Types are formed from two constructors:
|
|
24
|
+
|
|
25
|
+
1. **Product** – written `{ T₁ l₁, T₂ l₂, … }`
|
|
26
|
+
represents records with fixed labeled fields.
|
|
27
|
+
|
|
28
|
+
2. **Union** – written `< T₁ l₁, T₂ l₂, … >`
|
|
29
|
+
represents a choice between labeled alternatives.
|
|
30
|
+
|
|
31
|
+
Both are finite and fully explicit.
|
|
32
|
+
Every type denotes a finite tree automaton whose accepted trees are the possible values of that type.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## **2.3 Special and limiting cases**
|
|
37
|
+
|
|
38
|
+
1. **Empty product**
|
|
39
|
+
`{}` has no fields.
|
|
40
|
+
It represents the type that admits exactly one value, called *unit*.
|
|
41
|
+
There is nothing exceptional about the type and its value; it is simply the degenerate case of a product with zero fields.
|
|
42
|
+
|
|
43
|
+
2. **Empty union**
|
|
44
|
+
`<>` has no variants.
|
|
45
|
+
It represents a type with no possible values.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## **2.4 Projections**
|
|
50
|
+
|
|
51
|
+
**Dot** notation, e.g.,
|
|
52
|
+
|
|
53
|
+
```k
|
|
54
|
+
. field_name
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
is used for extracting the value of a field from a record (product type value).
|
|
58
|
+
**Div** notation, e.g.,
|
|
59
|
+
|
|
60
|
+
```k
|
|
61
|
+
/ variant_name
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
is used for asserting a particular variant of a union and extracting its value.
|
|
65
|
+
Product type `{ T₁ l₁, T₂ l₂, … , Tₙ lₙ }` naturally defines `n` partial functions: `.l₁, .l₂, … , .lₙ`,
|
|
66
|
+
and union type `< T₁ l₁, T₂ l₂, … , Tₙ lₙ >` naturally defines `n` partial functions `/l₁, /l₂, … , /lₙ`.
|
|
67
|
+
Those partial functions are called **projections** and they constitute the basis for the definition
|
|
68
|
+
of all other partial functions in the `k` language.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## **2.5 Functions**
|
|
73
|
+
|
|
74
|
+
Expressions combine partial functions using the following operators:
|
|
75
|
+
|
|
76
|
+
1. **Composition** `(f₁ f₂ …)` — sequential application.
|
|
77
|
+
2. **Union** `< f₁, f₂, … >` — try each in order, first defined wins.
|
|
78
|
+
3. **Product (parallel)** `{ f₁ l₁, f₂ l₂, … }` — apply all to the same input, succeed only if all succeed.
|
|
79
|
+
4. **Variant construction** `| tag` — lift the input as a variant `tag` of a union type.
|
|
80
|
+
|
|
81
|
+
Parentheses around a composition may be omitted except for the empty composition `()` — the identity function.
|
|
82
|
+
Empty product, `{ }`, defines a constant function (ignoring its input) returning *unit*.
|
|
83
|
+
|
|
84
|
+
It is important to notice that after the three markers: `dot (.)`, `div (/)`, or `pipe (|)`, there must be a constant label literal. For that reason, it is possible and advised not to leave any blanks after the marker, e.g.:
|
|
85
|
+
|
|
86
|
+
```k-lang
|
|
87
|
+
.field /'a-tag' |"strange and long tag name ✅"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## **2.6 Example**
|
|
93
|
+
|
|
94
|
+
```k-lang
|
|
95
|
+
$ bool = < {} true, {} false >;
|
|
96
|
+
true = {} |true $ bool;
|
|
97
|
+
false = {} |false $ bool;
|
|
98
|
+
neg = $ bool < /true false, /false true >;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
This defines a "two-variant" union type and three functions: two constants and one transformation exchanging the variants.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## **2.7 Summary**
|
|
106
|
+
|
|
107
|
+
* All types describe tree shapes.
|
|
108
|
+
* As type expression, `{}` is the empty product type (with one value, called *unit*).
|
|
109
|
+
* Functions, not values, are the only expressions in `k`.
|
|
110
|
+
|
|
111
|
+
---
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Chapter 3 — Types as Finite Automata
|
|
2
|
+
|
|
3
|
+
## **3.1 Motivation**
|
|
4
|
+
|
|
5
|
+
A type in `k` describes a set of finite labeled trees, which can be recognized by a finite tree automaton (FTA). Equivalently, a type definition can be seen as a Context-Free Grammar (CFG), where the values of the type are the derivation trees of the grammar.
|
|
6
|
+
|
|
7
|
+
For example, the recursive type definition of a `list`:
|
|
8
|
+
|
|
9
|
+
```k-lang
|
|
10
|
+
$ bool = < {} true, {} false >;
|
|
11
|
+
$ list = < {} nil, { bool head, list tail } cons >;
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
corresponds to the following 4-rule grammar:
|
|
15
|
+
|
|
16
|
+
```bnf
|
|
17
|
+
1: <bool> ::= {} |true
|
|
18
|
+
2: <bool> ::= {} |false
|
|
19
|
+
3: <list> ::= {} |nil
|
|
20
|
+
4: <list> ::= { <bool> head, <list> tail } |cons
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
A value of type `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
|
+
|
|
25
|
+
```
|
|
26
|
+
<list>
|
|
27
|
+
-- (rule 4) --> { <bool> head, <list> tail } |cons
|
|
28
|
+
| |
|
|
29
|
+
| -- (rule 3) --> {} |nil
|
|
30
|
+
|
|
|
31
|
+
-- (rule 1) --> {} |true
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This derivation tree corresponds to the value generated by constant function: `{ {} |true head, {} |nil tail } |cons`.
|
|
35
|
+
|
|
36
|
+
Representing types as automata (or CFGs) provides each type with a well-defined structure, independent of the names used in the source code. This allows for canonical normal forms and for comparing types for equality by structure alone.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## **3.2 States and Transitions**
|
|
41
|
+
|
|
42
|
+
Each type definition introduces one or more *states* in the automaton. A union or a product definition corresponds to a state, and the variants or fields correspond to transitions to other states.
|
|
43
|
+
|
|
44
|
+
For example, consider the `$bool` type:
|
|
45
|
+
|
|
46
|
+
```k-lang
|
|
47
|
+
$ bool = < {} true, {} false >;
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
This definition translates to an automaton with two states:
|
|
51
|
+
|
|
52
|
+
- A root state, let's call it `C0`, representing the `$bool` type itself (a union).
|
|
53
|
+
- A state `C1` representing the empty product `{}`.
|
|
54
|
+
|
|
55
|
+
From the root state `C0`, there are two transitions:
|
|
56
|
+
|
|
57
|
+
- A transition labeled `true` to state `C1`.
|
|
58
|
+
- A transition labeled `false` to state `C1`.
|
|
59
|
+
|
|
60
|
+
`C0` is the root state of the type, and `C1` is a leaf state, representing an empty value.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## **3.3 Canonical Form**
|
|
65
|
+
|
|
66
|
+
Different type expressions can describe the same automaton. For example:
|
|
67
|
+
|
|
68
|
+
```k-lang
|
|
69
|
+
$ bool = < {} false, {} true >;
|
|
70
|
+
$ pair = { bool x, bool y };
|
|
71
|
+
$ pair2 = { < {} true, {} false > x, bool y };
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The types `pair` and `pair2` are structurally equivalent because `$bool` is defined as `< {} true, {} false >`, making the definition of `x` in `pair2` identical to the standalone `$bool` type used in `pair`. 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 type structure.
|
|
75
|
+
|
|
76
|
+
The canonical form is generated by traversing the type's graph structure starting from its root state. The process ensures a unique representation by following a consistent ordering:
|
|
77
|
+
|
|
78
|
+
1. **Start at the Root**: Assign the number `C0` to the root state of the type.
|
|
79
|
+
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
|
+
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
|
+
4. **Complete**: Continue until all reachable states have been assigned a unique number.
|
|
82
|
+
|
|
83
|
+
This traversal produces a unique and deterministic numbering for any finite directed graph, ensuring that any two structurally identical types will have the exact same canonical representation.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## **3.4 Examples**
|
|
88
|
+
|
|
89
|
+
For a type representing binary natural numbers:
|
|
90
|
+
|
|
91
|
+
```k-lang
|
|
92
|
+
$ bnat = < bnat 0, bnat 1, {} _ >;
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
the canonical form is:
|
|
96
|
+
|
|
97
|
+
```k-lang
|
|
98
|
+
$C0 = < C0 "0", C0 "1", C1 "_" >;
|
|
99
|
+
$C1 = {};
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
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.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## **3.5 Normalization Process**
|
|
107
|
+
|
|
108
|
+
When compiling a program, the following steps are taken to normalize types:
|
|
109
|
+
|
|
110
|
+
1. **Collect**: Gather all type definitions from the program.
|
|
111
|
+
2. **Expand**: Recursively replace all named types with their underlying definitions until only products and unions remain.
|
|
112
|
+
3. **Deduplicate**: Eliminate duplicate type structures by comparing them structurally.
|
|
113
|
+
4. **Canonicalize**: Assign stable state numbers to the unique types to produce their canonical text representation.
|
|
114
|
+
|
|
115
|
+
This process is deterministic, ensuring that the same type structure always produces the exact same canonical form.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## **3.6 Hash-Based Naming**
|
|
120
|
+
|
|
121
|
+
To create a globally unique and stable identifier for each type, the compiler computes a hash of its canonical representation. This hash becomes the official, unambiguous name of the type.
|
|
122
|
+
|
|
123
|
+
For example:
|
|
124
|
+
|
|
125
|
+
```text
|
|
126
|
+
Canonical Form: $C0=<C0"0",C0"1",C1"_">;$C1={}
|
|
127
|
+
↓
|
|
128
|
+
Hash
|
|
129
|
+
↓
|
|
130
|
+
Identifier: @VtPHxGf5GNMzzyVFxtv7gegFfJRYapBGtCeyV56bs5Zb
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Program objects can then refer to types by their hash-based identifiers (prefixed with `@`) without ambiguity.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## **3.7 Interpretation**
|
|
138
|
+
|
|
139
|
+
The canonical representation of a type can be interpreted as:
|
|
140
|
+
|
|
141
|
+
- A finite set of states, `C0…Cn`.
|
|
142
|
+
- Each state is either a product (a record with named fields) or a union (a set of variants).
|
|
143
|
+
- Transitions between states are labeled with strings (field or variant names).
|
|
144
|
+
|
|
145
|
+
Every value of a given type is a finite tree that is accepted by this automaton.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## **3.8 Summary**
|
|
150
|
+
|
|
151
|
+
- Types in `k` denote sets of finite, labeled trees.
|
|
152
|
+
- Every type can be expressed as a finite tree automaton or a context-free grammar.
|
|
153
|
+
- The canonical form eliminates naming differences, providing a single representation for structurally identical types.
|
|
154
|
+
- Hash-based naming gives each unique type a stable and globally unique identifier.
|
|
155
|
+
|
|
156
|
+
---
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Chapter 4 — Partial Functions and Composition
|
|
2
|
+
|
|
3
|
+
## **4.1 Partial functions**
|
|
4
|
+
|
|
5
|
+
A **partial function** is a mapping that may be undefined for some inputs.
|
|
6
|
+
In `k`, every expression denotes such a function.
|
|
7
|
+
If a function is undefined for a given input, the evaluation process halts at that point, producing no result.
|
|
8
|
+
|
|
9
|
+
There is no notion of error or exception.
|
|
10
|
+
Undefined means simply “no output”.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## **4.2 Composition**
|
|
15
|
+
|
|
16
|
+
Composition combines two or more partial functions sequentially.
|
|
17
|
+
If `f` and `g` are functions, `(f g)` means “apply `f`, then apply `g` to the result”.
|
|
18
|
+
|
|
19
|
+
A composition `(f g)` is defined on a value `x` if and only if:
|
|
20
|
+
|
|
21
|
+
* `f` is defined on `x`, and
|
|
22
|
+
* `g` is defined on the result of `f(x)`.
|
|
23
|
+
|
|
24
|
+
Otherwise, the composition is undefined.
|
|
25
|
+
|
|
26
|
+
Composition is **associative**:
|
|
27
|
+
|
|
28
|
+
```math
|
|
29
|
+
(f (g h)) ≡ ((f g) h)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Therefore, parentheses are unnecessary, except for the special case of the **empty composition**, written `()`, which is the identity function:
|
|
33
|
+
|
|
34
|
+
```math
|
|
35
|
+
() x = x () = x
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## **4.3 Product composition**
|
|
41
|
+
|
|
42
|
+
Product composition creates a function that applies several subfunctions in parallel to the same input and gathers their results into a product value.
|
|
43
|
+
|
|
44
|
+
Syntax:
|
|
45
|
+
|
|
46
|
+
```math
|
|
47
|
+
{ f₁ l₁, f₂ l₂, …, fₙ lₙ }
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
This expression is defined on an input value if all component functions are defined on that input.
|
|
51
|
+
Its result is a product with fields labeled `l₁ … lₙ`, each containing the result of the corresponding function.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## **4.4 Union composition**
|
|
56
|
+
|
|
57
|
+
Union composition represents concurrent evaluation with fallback:
|
|
58
|
+
|
|
59
|
+
```k-lang
|
|
60
|
+
< f₁, f₂, …, fₙ >
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The result is defined for an input `x` if at least one subfunction is defined.
|
|
64
|
+
Evaluation proceeds left to right; the first defined result is used.
|
|
65
|
+
If none are defined, the result is undefined.
|
|
66
|
+
|
|
67
|
+
Example:
|
|
68
|
+
|
|
69
|
+
```k-lang
|
|
70
|
+
< /x, /y >
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
extracts variant `x` if present; otherwise `y` if present.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## **4.5 Constants**
|
|
78
|
+
|
|
79
|
+
A constant function is one that always returns the same value, regardless of its input.
|
|
80
|
+
Since `k` lacks a direct syntax for literal values, constants are created using functions that produce them.
|
|
81
|
+
|
|
82
|
+
For example, we can define functions that return `true` and `false`:
|
|
83
|
+
|
|
84
|
+
```k-lang
|
|
85
|
+
$ bool = < {} true, {} false >;
|
|
86
|
+
true_bool = {} |true $bool ;
|
|
87
|
+
false_bool = {} |false $bool ;
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
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.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## **4.6 Projection and Variant Value constructor**
|
|
95
|
+
|
|
96
|
+
Projection selects a field or a variant from a product or union.
|
|
97
|
+
It is written with a leading dot `.` or a leading slash `/`, respectively:
|
|
98
|
+
|
|
99
|
+
```k-lang
|
|
100
|
+
.x // Selects field 'x' from a product: { T x, ... }
|
|
101
|
+
/x // Extracts the value from a union variant 'x': < T x, ... >
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
If the input is a product, `.x` returns the value of field `x`. If the input is a union, `/x` returns the value of variant `x`. In all other cases, the projection is undefined.
|
|
105
|
+
|
|
106
|
+
Variant value constructors for a given union type `T = <T₁ tag₁, T₂ tag₂, … >` are written as `|tag₁`, `|tag₂`, ….
|
|
107
|
+
|
|
108
|
+
```k-lang
|
|
109
|
+
|tag₁ // lift a value of type T₁ into a value of type T
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Projections and variant constructors are the most basic partial functions.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## **4.7 Derived combinations**
|
|
117
|
+
|
|
118
|
+
Complex functions are built by nesting compositions.
|
|
119
|
+
For example:
|
|
120
|
+
|
|
121
|
+
```k-lang
|
|
122
|
+
{ .x field1, .y |tag field2 }
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## **4.8 Identity and emptiness**
|
|
128
|
+
|
|
129
|
+
The empty composition `()` is the identity function.
|
|
130
|
+
The empty union `<>` is the always-undefined function.
|
|
131
|
+
The empty product `{}` is the constant function returning the unit value.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## **4.9 Summary**
|
|
136
|
+
|
|
137
|
+
* In `k`, all expressions denote **partial functions**.
|
|
138
|
+
* An undefined result simply means “no output,” not an error.
|
|
139
|
+
* **Composition** `(f g)` applies functions sequentially and is associative, so parentheses are often optional.
|
|
140
|
+
* The empty composition `()` is the **identity function**.
|
|
141
|
+
* **Product composition** `{...}` runs functions in parallel and gathers their results.
|
|
142
|
+
* **Union composition** `<...>` tries functions in order, returning the first successful result.
|
|
143
|
+
* **Projections** (`.x`, `/x`) are fundamental building blocks for accessing data structures.
|
|
144
|
+
* **Variant constructor** (`|tag`) allows lifting a value into a variant type value.
|
|
145
|
+
|
|
146
|
+
---
|