@fraczak/k 5.1.2 → 6.0.1
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/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/a.html +398 -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-combined.html +3798 -0
- package/DOCS/book-combined.md +3745 -0
- package/DOCS/book-combined.pdf +0 -0
- package/DOCS/book-combined.tex +5682 -0
- package/DOCS/book.html +65 -0
- package/DOCS/book.md +54 -0
- package/DOCS/book.pdf +0 -0
- package/DOCS/book.tex +150 -0
- package/NAT.k~ +452 -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.html +471 -0
- package/codecs/BINARY_FORMAT.md +53 -0
- package/codecs/POLYMORPHIC_BINARY_FORMAT.html +355 -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/ieee.klib +0 -0
- 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-lock.json +4176 -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 +13 -6
- package/parser.jison +27 -46
- package/parser.mjs +68 -100
- package/pretty.mjs +21 -40
- package/repl2.mjs +662 -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 +106 -0
- package/test.mjs +45 -70
- package/tests.sh +10 -1
- package/type_registry/registry.mjs~ +105 -0
- package/type_registry/typeParser.jison~ +132 -0
- 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/.codex
ADDED
|
File without changes
|
|
@@ -2,7 +2,7 @@ import { t, in_out } from './index.mjs';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import assert from 'assert';
|
|
4
4
|
|
|
5
|
-
// t(fs.readFileSync("./Examples/blowup.k"
|
|
5
|
+
// t(fs.readFileSync("./Examples/blowup.k", "utf8"), (annotated) => {
|
|
6
6
|
// // console.log(JSON.stringify(annotated,null,2));
|
|
7
7
|
// const {input,output} = in_out(annotated);
|
|
8
8
|
// console.log(input);
|
|
@@ -13,8 +13,8 @@ import assert from 'assert';
|
|
|
13
13
|
// });
|
|
14
14
|
|
|
15
15
|
t(`
|
|
16
|
-
B = {
|
|
17
|
-
A = <
|
|
16
|
+
B = {}|u A;
|
|
17
|
+
A = ?X < /a, /b ?X A, /c |z ?X A, B >;
|
|
18
18
|
A
|
|
19
19
|
`, (annotated) => {
|
|
20
20
|
// console.log(JSON.stringify(annotated,null,2));
|
|
@@ -2,10 +2,10 @@ import { t, in_out } from './index.mjs';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import assert from 'assert';
|
|
4
4
|
|
|
5
|
-
t(fs.readFileSync("./Examples/bnat
|
|
5
|
+
t(fs.readFileSync("./Examples/bnat.k", "utf8"), (annotated) => {
|
|
6
6
|
// console.log(JSON.stringify(annotated,null,2));
|
|
7
7
|
const {input,output} = in_out(annotated);
|
|
8
|
-
console.log(output);
|
|
8
|
+
// console.log(output);
|
|
9
9
|
assert.equal(output.type, annotated.representatives["bnat"]);
|
|
10
10
|
assert.equal(input.type, annotated.representatives["pair"]);
|
|
11
11
|
console.log("OK");
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import assert from 'assert';
|
|
2
|
+
import { parseValue } from '../valueIO.mjs';
|
|
3
|
+
import { encodeToWire, decodeWire } from '../codecs/runtime/prefix-codec.mjs';
|
|
4
|
+
import { Product, Variant } from '../Value.mjs';
|
|
5
|
+
|
|
6
|
+
const value = parseValue('{a:{b:x,c:{}}}');
|
|
7
|
+
const repeatedClosedValue = parseValue('{a:{m:{},n:{}},b:{m:{},n:{}}}');
|
|
8
|
+
const repeatedOpenValue = parseValue('{a:x,b:x}');
|
|
9
|
+
|
|
10
|
+
const defaultWire = decodeWire(encodeToWire(value, null));
|
|
11
|
+
assert.deepEqual(defaultWire.pattern, [
|
|
12
|
+
["open-union", [["a", 1]]],
|
|
13
|
+
["closed-product", [["b", 2], ["c", 3]]],
|
|
14
|
+
["open-union", [["x", 3]]],
|
|
15
|
+
["closed-product", []]
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
const explicitProductWire = decodeWire(encodeToWire(value, [
|
|
19
|
+
["open-product", [["a", 1]]],
|
|
20
|
+
["any", []]
|
|
21
|
+
]));
|
|
22
|
+
assert.deepEqual(explicitProductWire.pattern, [
|
|
23
|
+
["open-product", [["a", 1]]],
|
|
24
|
+
["closed-product", [["b", 2], ["c", 3]]],
|
|
25
|
+
["open-union", [["x", 3]]],
|
|
26
|
+
["closed-product", []]
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
const decoded = explicitProductWire.value;
|
|
30
|
+
assert(decoded instanceof Product);
|
|
31
|
+
assert(decoded.product.a instanceof Product);
|
|
32
|
+
assert(decoded.product.a.product.b instanceof Variant);
|
|
33
|
+
assert.equal(decoded.product.a.product.b.tag, "x");
|
|
34
|
+
|
|
35
|
+
const repeatedClosedWire = decodeWire(encodeToWire(repeatedClosedValue, null));
|
|
36
|
+
assert.deepEqual(repeatedClosedWire.pattern, [
|
|
37
|
+
["closed-product", [["a", 1], ["b", 1]]],
|
|
38
|
+
["closed-product", [["m", 2], ["n", 2]]],
|
|
39
|
+
["closed-product", []]
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
const repeatedOpenWire = decodeWire(encodeToWire(repeatedOpenValue, null));
|
|
43
|
+
assert.deepEqual(repeatedOpenWire.pattern, [
|
|
44
|
+
["closed-product", [["a", 1], ["b", 3]]],
|
|
45
|
+
["open-union", [["x", 2]]],
|
|
46
|
+
["closed-product", []],
|
|
47
|
+
["open-union", [["x", 2]]]
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
console.log("OK");
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import assert from "assert";
|
|
2
|
+
import { annotate } from "../index.mjs";
|
|
3
|
+
|
|
4
|
+
const script = `
|
|
5
|
+
f = .x;
|
|
6
|
+
g = f;
|
|
7
|
+
g
|
|
8
|
+
`;
|
|
9
|
+
|
|
10
|
+
const autoAnnotated = annotate(script);
|
|
11
|
+
assert.deepEqual(
|
|
12
|
+
autoAnnotated.compileStats.sccs.map(({ strategy }) => strategy),
|
|
13
|
+
["single_pass", "single_pass", "single_pass"]
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const fixedPointAnnotated = annotate(script, {
|
|
17
|
+
convergence: { strategy: "fixed_point" }
|
|
18
|
+
});
|
|
19
|
+
assert.deepEqual(
|
|
20
|
+
fixedPointAnnotated.compileStats.sccs.map(({ strategy }) => strategy),
|
|
21
|
+
["fixed_point", "fixed_point", "fixed_point"]
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
console.log("OK");
|
|
@@ -1,40 +1,43 @@
|
|
|
1
1
|
import { t, in_out } from './index.mjs';
|
|
2
|
+
import { hash } from '../hash.mjs';
|
|
2
3
|
import assert from 'assert';
|
|
3
4
|
|
|
4
5
|
t(`
|
|
5
6
|
$b = < {} true, {} false > ;
|
|
6
7
|
$pair = { b one, b two } ;
|
|
7
|
-
|
|
8
|
+
$bit = <{} 0, {} 1> ;
|
|
9
|
+
1 = {} |1 $bit;
|
|
8
10
|
$b {1 one, () two, () c} .one
|
|
9
11
|
|
|
10
12
|
`, (annotated) => {
|
|
11
13
|
const {input,output} = in_out(annotated);
|
|
12
14
|
// console.log({input,output});
|
|
13
15
|
assert.equal(input.type, annotated.representatives["b"]);
|
|
14
|
-
assert.equal(output.type, "
|
|
16
|
+
assert.equal(output.type, annotated.representatives["bit"]);
|
|
15
17
|
console.log("OK");
|
|
16
18
|
});
|
|
17
19
|
|
|
18
20
|
t(`
|
|
19
|
-
$
|
|
20
|
-
$a
|
|
21
|
+
$bit = <{} 0, {} 1> ;
|
|
22
|
+
$a = < bit true, bit false > ;
|
|
23
|
+
$a /true
|
|
21
24
|
`, (annotated) => {
|
|
22
25
|
const {input,output} = in_out(annotated);
|
|
23
26
|
console.log({input,output});
|
|
24
27
|
});
|
|
25
28
|
|
|
26
29
|
t(`
|
|
27
|
-
x =
|
|
28
|
-
xy = x
|
|
30
|
+
x = /x;
|
|
31
|
+
xy = x/y;
|
|
29
32
|
f = {
|
|
30
|
-
{
|
|
31
|
-
{
|
|
33
|
+
{} | y | x xy i,
|
|
34
|
+
{} | y | x xy b
|
|
32
35
|
};
|
|
33
36
|
f .b
|
|
34
37
|
`, (annotated) => {
|
|
35
38
|
const {input,output} = in_out(annotated);
|
|
36
39
|
console.log({input,output});
|
|
37
40
|
assert.equal(input.pattern, '(...)');
|
|
38
|
-
assert.equal(output.type, "
|
|
41
|
+
assert.equal(output.type, hash("$C0={};"));
|
|
39
42
|
console.log("OK");
|
|
40
43
|
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import assert from 'assert';
|
|
2
|
+
import { annotate } from '../index.mjs';
|
|
3
|
+
|
|
4
|
+
function succeeds(script) {
|
|
5
|
+
assert.doesNotThrow(() => annotate(script));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function fails(script) {
|
|
9
|
+
assert.throws(() => annotate(script));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
succeeds('?(...)');
|
|
13
|
+
succeeds('?{...}');
|
|
14
|
+
succeeds('?<...>');
|
|
15
|
+
succeeds('?{}');
|
|
16
|
+
succeeds('?<>');
|
|
17
|
+
|
|
18
|
+
fails('?()');
|
|
19
|
+
fails('?(X x, ...)');
|
|
20
|
+
|
|
21
|
+
console.log("OK");
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { t, in_out } from './index.mjs';
|
|
2
2
|
import assert from 'assert';
|
|
3
3
|
|
|
4
|
+
t(` < /a, () > `, (annotated) => {
|
|
5
|
+
const {input,output} = in_out(annotated);
|
|
6
|
+
assert.equal(input.pattern, "<...>");
|
|
7
|
+
assert.equal(output, input);
|
|
8
|
+
console.log("OK");
|
|
9
|
+
});
|
|
4
10
|
t(` < .a, () > `, (annotated) => {
|
|
5
11
|
const {input,output} = in_out(annotated);
|
|
6
|
-
assert.equal(input.pattern, "
|
|
12
|
+
assert.equal(input.pattern, "{...}");
|
|
7
13
|
assert.equal(output, input);
|
|
8
14
|
console.log("OK");
|
|
9
15
|
});
|
|
10
16
|
|
|
11
|
-
// Notice that the following are equivalent: '<(),
|
|
17
|
+
// Notice that the following are equivalent: '<(), /a>', '<()>', and '()';
|
|
@@ -2,7 +2,7 @@ import { t, in_out } from './index.mjs';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import assert from 'assert';
|
|
4
4
|
|
|
5
|
-
t(fs.readFileSync("./Examples/nat.k"
|
|
5
|
+
t(fs.readFileSync("./Examples/nat.k", "utf8"), (annotated) => {
|
|
6
6
|
const {input,output} = in_out(annotated);
|
|
7
7
|
assert.equal(output.type, annotated.representatives["nat"]);
|
|
8
8
|
assert.equal(input.type, annotated.representatives["nat"]);
|
|
@@ -2,9 +2,9 @@ import { t, in_out } from './index.mjs';
|
|
|
2
2
|
import assert from 'assert';
|
|
3
3
|
|
|
4
4
|
t(`$b = < {} true, {} false > ;
|
|
5
|
-
true = {
|
|
6
|
-
false = {
|
|
7
|
-
not = $b <
|
|
5
|
+
true = {} |true $b;
|
|
6
|
+
false = {} |false $b;
|
|
7
|
+
not = $b < /true false, /false true >;
|
|
8
8
|
not not
|
|
9
9
|
`, (annotated) => {
|
|
10
10
|
const {input,output} = in_out(annotated);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import k from "../index.mjs";
|
|
3
|
+
import { Product, Variant, mergePatterns, withPattern } from "../Value.mjs";
|
|
4
|
+
import { decodeWire, encodeToWire } from "../codecs/runtime/prefix-codec.mjs";
|
|
5
|
+
import run from "../run.mjs";
|
|
6
|
+
import codes from "../codes.mjs";
|
|
7
|
+
|
|
8
|
+
const INT_PATTERN = [
|
|
9
|
+
["closed-union", [["+", 1], ["-", 1]]],
|
|
10
|
+
["closed-union", [["0", 1], ["1", 1], ["_", 2]]],
|
|
11
|
+
["closed-product", []]
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
const script = `
|
|
15
|
+
$ bits = < {} _, bits 0, bits 1 >;
|
|
16
|
+
$ int = < bits +, bits - >;
|
|
17
|
+
{}|_|0|1|+ $int
|
|
18
|
+
`;
|
|
19
|
+
|
|
20
|
+
const result = k.compile(script)(new Product({}));
|
|
21
|
+
assert.deepEqual(result.pattern, INT_PATTERN);
|
|
22
|
+
|
|
23
|
+
const decoded = decodeWire(encodeToWire(result, result.pattern));
|
|
24
|
+
assert.deepEqual(decoded.pattern, INT_PATTERN);
|
|
25
|
+
|
|
26
|
+
const two = new Variant("+",
|
|
27
|
+
new Variant("1",
|
|
28
|
+
new Variant("0",
|
|
29
|
+
new Variant("_", new Product({}))
|
|
30
|
+
)
|
|
31
|
+
)
|
|
32
|
+
);
|
|
33
|
+
const witnessPattern = [
|
|
34
|
+
["closed-union", [["+", 1]]],
|
|
35
|
+
["closed-union", [["1", 2]]],
|
|
36
|
+
["closed-union", [["0", 3]]],
|
|
37
|
+
["closed-union", [["_", 4]]],
|
|
38
|
+
["closed-product", []]
|
|
39
|
+
];
|
|
40
|
+
const overExpandedSingleton = mergePatterns(INT_PATTERN, witnessPattern);
|
|
41
|
+
const decodedMerged = decodeWire(encodeToWire(two, overExpandedSingleton));
|
|
42
|
+
assert.deepEqual(decodedMerged.pattern, INT_PATTERN);
|
|
43
|
+
|
|
44
|
+
const identityResult = k.compile("()")(withPattern(two, INT_PATTERN));
|
|
45
|
+
assert.deepEqual(identityResult.pattern, INT_PATTERN);
|
|
46
|
+
|
|
47
|
+
assert.throws(
|
|
48
|
+
() => k.compile(".x")(withPattern(two, INT_PATTERN)),
|
|
49
|
+
/Type Error in 'comp'.*Value envelope does not intersect expression input pattern/s
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const projectionScript = `
|
|
53
|
+
$ bits = < {} _, bits 0, bits 1 >;
|
|
54
|
+
$ int = < bits +, bits - >;
|
|
55
|
+
$int /+
|
|
56
|
+
`;
|
|
57
|
+
const annotated = k.annotate(projectionScript);
|
|
58
|
+
run.defs = annotated;
|
|
59
|
+
const projected = run(
|
|
60
|
+
codes.find,
|
|
61
|
+
annotated.rels.__main__.def,
|
|
62
|
+
two,
|
|
63
|
+
annotated.rels.__main__.typePatternGraph
|
|
64
|
+
);
|
|
65
|
+
assert.deepEqual(projected.pattern, [
|
|
66
|
+
["closed-union", [["0", 0], ["1", 0], ["_", 1]]],
|
|
67
|
+
["closed-product", []]
|
|
68
|
+
]);
|
|
@@ -6,11 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
The language describes "partial first-order functions" on "printable" values.
|
|
8
8
|
The printable values can be seen as rooted, edge-labeled trees, intuitively similar to an
|
|
9
|
-
XML or a JSON document. The values are always typed
|
|
9
|
+
XML or a JSON document. The values are always typed; in the current codec-aware
|
|
10
|
+
runtime, a value may carry a pattern describing the family of types compatible
|
|
11
|
+
with that tree.
|
|
10
12
|
|
|
11
13
|
### Types (codes)
|
|
12
14
|
|
|
13
|
-
Formally, a _type_ is a (subclass of
|
|
15
|
+
Formally, a _type_ is a (subclass of finite tree automata. The type defines a set of its values,
|
|
14
16
|
which corresponds to the set of trees accepted by the automaton.
|
|
15
17
|
Therefore, every type admits a unique normal form in terms of its minimal deterministic tree automaton.
|
|
16
18
|
|
|
@@ -19,6 +21,9 @@ Types are defined by two constructs:
|
|
|
19
21
|
1. Product
|
|
20
22
|
2. Union (also called tagged or disjoint union)
|
|
21
23
|
|
|
24
|
+
> Notation: We use native k-like notation as canonical — products `{ T l, ... }` and unions `< T t, ... >`.
|
|
25
|
+
> For convenience, JSON-like forms `{ l: T, ... }` and `< t: T, ... >` are also supported and equivalent in meaning.
|
|
26
|
+
|
|
22
27
|
```bnf
|
|
23
28
|
type ::= name | '{' type_label_list '}' | '<' type_label_list '>'
|
|
24
29
|
type_label_list ::= /* empty */ | ( type label ',' )* type label
|
|
@@ -30,10 +35,10 @@ Given a finite (possibly empty) set of types `t1, t2, ..., tn` and a set of pair
|
|
|
30
35
|
|
|
31
36
|
- by `{ t1 l1, t2 l2, ..., tn ln }`, we define a _product type_ with exactly `n`
|
|
32
37
|
_projection_ functions: `.l1`, `.l2`, `...`, `.ln`.
|
|
33
|
-
Each projection function
|
|
38
|
+
Each projection function maps a value of type `{t1 l1, t2 l2, ..., tn ln}`
|
|
34
39
|
into a value of type `t1`, `t2`, `...`, `tn`, respectively.
|
|
35
|
-
- by `< t1 l1, t2 l2, ..., tn ln >`, we define a _union type_ with exactly `n` projection functions
|
|
36
|
-
|
|
40
|
+
- by `< t1 l1, t2 l2, ..., tn ln >`, we define a _union type_ with exactly `n` projection functions `/l1`, `/l2`, `...`, `/ln`,
|
|
41
|
+
maps a value of type `<t1 l1, t2 l2, ..., tn ln>` into a value of type `t1`, `t2`, `...`, `tn`, respectively.
|
|
37
42
|
|
|
38
43
|
Intuitively, the projection functions on a product type are all total (meaning, they are defined for every value of the
|
|
39
44
|
input product type), whereas in the case of a union type, exactly one projection function is defined
|
|
@@ -41,20 +46,31 @@ for a given value of the union type.
|
|
|
41
46
|
|
|
42
47
|
Some properties of these types:
|
|
43
48
|
|
|
44
|
-
1.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
1. The empty product type, `{}`, has a single value, called the _unit_.
|
|
50
|
+
2. The empty union type, `<>`, has no values.
|
|
51
|
+
|
|
52
|
+
#### Variant (union) value literal convention
|
|
53
|
+
|
|
54
|
+
- Variant values are written using "|" (pipe) followed by the variant tag.
|
|
55
|
+
- Unit variant `` `{}` `` | tag (e.g., `{} | nil`, `{} | zero`)
|
|
56
|
+
- Variant with payload `v` at label `tag`: ` v | tag `
|
|
57
|
+
- Example (list): with `$list = < {} nil, {X car, list cdr} cons >`:
|
|
58
|
+
- Empty list []: `{}|nil`
|
|
59
|
+
- Singleton `[v]`: `{ v car, {}|nil cdr } | cons`
|
|
60
|
+
- Angle brackets are for type definitions and merge expressions; use "`| tag`" for a variant construction.
|
|
61
|
+
|
|
62
|
+
#### Equivalence of types (bisimilarity)
|
|
63
|
+
|
|
64
|
+
Two (possibly recursive) codes are equivalent iff they are bisimilar over their definition graphs. Concretely, there exists a relation B such that `(t1, t2) ∈ B` if and only if:
|
|
65
|
+
- t1 and t2 have exactly the same set of labels/tags;
|
|
66
|
+
- t1 and t2 are simultaneously products or simultaneously unions;
|
|
67
|
+
- for each label/tag `ℓ` in the set, the subcodes under `ℓ` are again related by B.
|
|
52
68
|
|
|
53
69
|
### Filters (patterns)
|
|
54
70
|
|
|
55
|
-
A _filter_ is a way of representing a
|
|
71
|
+
A _filter_ is a way of representing a _pattern_, i.e, a set of types sharing some structure.
|
|
56
72
|
For example, if I wanted to refer to all product types that have a field `f` of type `T`,
|
|
57
|
-
I would write
|
|
73
|
+
I would write: `?{ T f, ... }`. In general, a filter is defined by:
|
|
58
74
|
|
|
59
75
|
```bnf
|
|
60
76
|
filter ::= name | '$' type_expr | '{' filter_label_list '}'
|
|
@@ -71,8 +87,7 @@ Examples:
|
|
|
71
87
|
( ... ) -- any type
|
|
72
88
|
{ ... } -- any product type
|
|
73
89
|
( X x, X y ) -- any type with two fields of the same type
|
|
74
|
-
< X x, ... > = X -- a (recursive) type, 'X', with variant 'x'
|
|
75
|
-
-- of the same type 'X'
|
|
90
|
+
< X x, ... > = X -- a (recursive) variant type, 'X', with variant 'x' of the same type 'X'
|
|
76
91
|
```
|
|
77
92
|
|
|
78
93
|
### Partial functions
|
|
@@ -86,7 +101,7 @@ There are three ways of combining partial functions:
|
|
|
86
101
|
and `g` is defined on value `y` producing `z`, then `(f g)` is defined on value `x` producing `z`.
|
|
87
102
|
2. __Union__: we write `< f1, f2 >` for a union of two functions `f1` and `f2`, meaning that
|
|
88
103
|
if `f1` is defined on value `x` producing `y`, then `< f1, f2 >`
|
|
89
|
-
is defined on value `x` producing `y`. Otherwise, i.e., when `f1` is not defined for `x`, `< f1 f2 >` acts as `f2`.
|
|
104
|
+
is defined on value `x` producing `y`. Otherwise, i.e., when `f1` is not defined for `x`, `< f1, f2 >` acts as `f2`.
|
|
90
105
|
3. __Product__: we write `{f1 lab1, f2 lab2 }` for a product of two functions `f1` and `f2`,
|
|
91
106
|
meaning that if `f1` and `f2` are both defined on value `x` producing `y1` and `y2`,
|
|
92
107
|
respectively, then `{f1 lab1, f2 lab2 }` is defined on value `x` producing
|
|
@@ -109,7 +124,7 @@ type_definition ::= '$' type_name '=' type ';'
|
|
|
109
124
|
function_definition ::= name '=' expression ';'
|
|
110
125
|
expression ::= name | '$' type | '?' filter
|
|
111
126
|
| projection | composition | union | product
|
|
112
|
-
projection ::= '.' label
|
|
127
|
+
projection ::= '.' label | '/' label
|
|
113
128
|
composition ::= '(' expression * ')'
|
|
114
129
|
union ::= '<' (expression ',') + expression '>'
|
|
115
130
|
product ::= '{' expr_label_list '}'
|
|
@@ -123,7 +138,7 @@ We assume that in a `kernel-core` program the names (for types, functions, and l
|
|
|
123
138
|
2. All defined function names are distinct.
|
|
124
139
|
3. All label names within a type definition or a `product` expression are locally distinct.
|
|
125
140
|
|
|
126
|
-
|
|
141
|
+
Filters and type expressions act as a type annotation, i.e., an identity
|
|
127
142
|
function defined only for the values of the corresponding types.
|
|
128
143
|
|
|
129
144
|
That's it.
|
|
@@ -141,7 +156,7 @@ Obviously, a function may have many different definitions so the hash-based name
|
|
|
141
156
|
This approach solves the problem of modules, imports, etc., and opens the door to a universal
|
|
142
157
|
registry of types (schemas) and functions.
|
|
143
158
|
|
|
144
|
-
## Typing and Polymorphism (codes and
|
|
159
|
+
## Typing and Polymorphism (codes and patterns)
|
|
145
160
|
|
|
146
161
|
Abstract Syntax Tree of a program consists of a dictionary of _type definitions_,
|
|
147
162
|
a dictionary of _function definitions_, and the final _main expression_.
|
|
@@ -154,7 +169,7 @@ representations for functions, so they could be reused.
|
|
|
154
169
|
|
|
155
170
|
The normalization steps are:
|
|
156
171
|
|
|
157
|
-
1. Build the _type graph_ from all types used by the program, i.e., used in _type definitions_
|
|
172
|
+
1. Build the _type graph_ from all types used by the program, i.e., used in _type definitions_
|
|
158
173
|
as well as type expressions used in _function definitions_ and the _main expression_.
|
|
159
174
|
2. Annotate the expressions with filters; every node of the AST is annotated with a pair of filters.
|
|
160
175
|
3. Turn the _singleton_ filters into types and add them to the _type graph_. Go to (2) unless no change.
|
|
@@ -165,23 +180,23 @@ The normalization steps are:
|
|
|
165
180
|
|
|
166
181
|
```k-repl
|
|
167
182
|
$ bit = < {} o, {} i >;
|
|
168
|
-
bit0 =
|
|
169
|
-
bit1 =
|
|
183
|
+
bit0 = | o $bit;
|
|
184
|
+
bit1 = | i $bit;
|
|
170
185
|
|
|
171
186
|
$ byte = { bit b0, bit b1, bit b2, bit b3 };
|
|
172
187
|
zero = bit0 { () b0, () b1, () b2, () b3 } $byte;
|
|
173
188
|
|
|
174
|
-
inc = $byte
|
|
189
|
+
inc = $ byte
|
|
175
190
|
<
|
|
176
|
-
{
|
|
177
|
-
{
|
|
178
|
-
{
|
|
179
|
-
{
|
|
180
|
-
{ bit1
|
|
191
|
+
{ bit0 overflown, { .b0/o bit1 b0, .b1 b1, .b2 b2, .b3 b3 } byte },
|
|
192
|
+
{ bit0 overflown, { bit0 b0, .b1/o bit1 b1, .b2 b2, .b3 b3 } byte },
|
|
193
|
+
{ bit0 overflown, { bit0 b0, bit0 b1, .b2/o bit1 b2, .b3 b3 } byte },
|
|
194
|
+
{ bit0 overflown, { bit0 b0, bit0 b1, bit0 b2, ,b3/o bit1 b3 } byte },
|
|
195
|
+
{ bit1 overflown, zero byte }
|
|
181
196
|
>
|
|
182
197
|
;
|
|
183
198
|
|
|
184
|
-
-- inc with overflown flag
|
|
199
|
+
-- inc with overflown flag
|
|
185
200
|
inc_o =
|
|
186
201
|
{ .byte inc inc, .overflown overflown }
|
|
187
202
|
{
|
|
@@ -195,8 +210,8 @@ inc3 = inc inc_o inc_o;
|
|
|
195
210
|
inc3
|
|
196
211
|
```
|
|
197
212
|
|
|
198
|
-
In the above program, we define
|
|
199
|
-
and
|
|
213
|
+
In the above program, we define type `bit` as union of two unit types,
|
|
214
|
+
and type `byte` as product, for simplicity, of four `bit`s.
|
|
200
215
|
|
|
201
216
|
Functions `bit0`, `bit1`, and `zero` are "constant polymorphic functions", meaning:
|
|
202
217
|
|
|
@@ -209,18 +224,18 @@ Functions `inc` and `inc3` are (non-polymorphic) functions of types
|
|
|
209
224
|
`$byte -> ${ bit overflown, byte byte }` and
|
|
210
225
|
`${ bit overflown, byte byte } -> ${ bit overflown, byte byte }`, respectively.
|
|
211
226
|
|
|
212
|
-
Function `inc_o` is a polymorphic function of type patterns: `?X -> ${ byte byte, bit overflown }`
|
|
227
|
+
Function `inc_o` is a polymorphic function of type patterns: `?X -> ${ byte byte, bit overflown }`
|
|
213
228
|
with following constraints:
|
|
214
229
|
|
|
215
|
-
- `?X` is a product
|
|
216
|
-
> `?
|
|
217
|
-
- `?Z` is a
|
|
218
|
-
>
|
|
230
|
+
- `?X` is a product type with at least two fields: `byte` and `overflown`, denoted by:
|
|
231
|
+
> `?{ $byte byte, Z overflown, ...}`;
|
|
232
|
+
- `?Z` is a union type with field `i` denoted by:
|
|
233
|
+
> `?< V i, ...>`;
|
|
219
234
|
- `V` is unconstrained, denoted by `(...)`;
|
|
220
235
|
|
|
221
|
-
We can write it as: `?
|
|
236
|
+
We can write it as: `?{$byte byte, <(...) i, ...> overflown, ...}`.
|
|
222
237
|
|
|
223
|
-
The target type `${ byte byte, bit overflown }`
|
|
238
|
+
The target type `${ byte byte, bit overflown }` corresponds to pattern `?{ $byte byte, $bit overflown }`.
|
|
224
239
|
Such a pattern is called _singleton pattern_, as only one type fits the pattern.
|
|
225
240
|
|
|
226
241
|
#### Example 2
|
|
@@ -229,12 +244,12 @@ Polymorphic list functions:
|
|
|
229
244
|
|
|
230
245
|
```k-repl
|
|
231
246
|
list? = ?< {} nil, {X car, Y cdr} cons > = Y;
|
|
232
|
-
nil = {
|
|
233
|
-
singleton = {
|
|
234
|
-
cons = {
|
|
235
|
-
nil? = list?
|
|
236
|
-
car = list?
|
|
237
|
-
cdr = list?
|
|
247
|
+
nil = {} |nil list?;
|
|
248
|
+
singleton = {() car, nil cdr} |cons list?;
|
|
249
|
+
cons = {.car car, .cdr cdr} | cons list?;
|
|
250
|
+
nil? = list? /nil nil;
|
|
251
|
+
car = list? /cons .car;
|
|
252
|
+
cdr = list? /cons .cdr;
|
|
238
253
|
```
|
|
239
254
|
|
|
240
255
|
For example, the filter annotation for `car` is:
|
|
@@ -272,16 +287,54 @@ The transformation is done by partial functions as defined in the language.
|
|
|
272
287
|
The non-recursive and tail-recursive (and even some non-tail recursive) functions can
|
|
273
288
|
be compiled into deterministic finite (pushdown) transducers.
|
|
274
289
|
|
|
275
|
-
### AND-OR graphs for
|
|
290
|
+
### AND-OR graphs for encoding and decoding codes
|
|
276
291
|
|
|
277
|
-
This could be generic and compact way to encode and decode typed values.
|
|
292
|
+
This could be a generic and compact way to encode and decode typed values.
|
|
278
293
|
The idea is to use _prefix codes_ (a class of languages such that no word is a prefix of
|
|
279
294
|
another word) to encode the values.
|
|
280
295
|
|
|
281
|
-
###
|
|
296
|
+
### Rust data structures
|
|
282
297
|
|
|
283
298
|
A type can be translated into a Rust data structure, and a function can be translated into a Rust function.
|
|
284
299
|
|
|
285
300
|
## Linking with Other Languages
|
|
286
301
|
|
|
287
|
-
## Streams and Arrays (Map-Reduce)
|
|
302
|
+
## Streams and Arrays (Map-Reduce)
|
|
303
|
+
|
|
304
|
+
## Bits
|
|
305
|
+
|
|
306
|
+
Extending `@string` into `@bits`.
|
|
307
|
+
|
|
308
|
+
```k-repl
|
|
309
|
+
$ bits = < {} _, bits 0, bits 1 >;
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Literals for `@bits` are:
|
|
313
|
+
|
|
314
|
+
- `0b` for 0 bits
|
|
315
|
+
- `0b10` for 2 bits
|
|
316
|
+
- `0xF` for 4 bits
|
|
317
|
+
- `0xF0` for 8 bits
|
|
318
|
+
- `0o1` for 3 bits
|
|
319
|
+
- `0o7` for 3 bits
|
|
320
|
+
- "" for 0 bits
|
|
321
|
+
- "ala" for 24 bits
|
|
322
|
+
|
|
323
|
+
### Two operations on `@bits`:
|
|
324
|
+
|
|
325
|
+
#### Eat `/`
|
|
326
|
+
|
|
327
|
+
- `$@bits / @bits` --- division, e.g., `0b1011 / 0b10` = `0b11`, `"abc" / "a"` = `"bc"`
|
|
328
|
+
|
|
329
|
+
#### Prepend `\`
|
|
330
|
+
|
|
331
|
+
- `$@bits \ @bits` --- multiplication, e.g., `0b11 \ 0b10` = `0b1011`, `"bc" \ "a"` = `"abc"`
|
|
332
|
+
|
|
333
|
+
Empty `bits` can be checked by
|
|
334
|
+
|
|
335
|
+
```k
|
|
336
|
+
|
|
337
|
+
kind = $@bits
|
|
338
|
+
< {/ 0b0 \ 0b0 starts_with_0}, {/ 0b1 \ 0b1 starts_with_1}, {() empty} >
|
|
339
|
+
$< @bits starts_with_0, @bits starts_with_1, @bits empty >;
|
|
340
|
+
```
|