@fraczak/k 3.0.2 → 4.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/BIG_PICTURE.md +42 -24
- package/Code-derivation-tests/blowup.mjs +27 -0
- package/Code-derivation-tests/bnat.mjs +4 -2
- package/Code-derivation-tests/built-in.mjs +1 -1
- package/Code-derivation-tests/dot.mjs +28 -3
- package/Code-derivation-tests/index.mjs +2 -2
- package/Code-derivation-tests/loop.mjs +1 -1
- package/Code-derivation-tests/nat.mjs +2 -2
- package/Code-derivation-tests/not-not.mjs +2 -2
- package/Code-derivation-tests/product.mjs +9 -5
- package/Code-derivation-tests/rlz.mjs +2 -2
- package/Code-derivation-tests/vector.mjs +7 -16
- package/Filters/bug.k +3 -0
- package/Filters/composing.k +15 -0
- package/Filters/filter.k +9 -0
- package/Graph.mjs +95 -0
- package/README.md +18 -15
- package/TYPING.md +365 -0
- package/codes.mjs +60 -8
- package/hash.mjs +6 -5
- package/index.mjs +11 -41
- package/k.mjs +1 -2
- package/package.json +1 -1
- package/parser.jison +22 -10
- package/parser.mjs +74 -65
- package/patterns.mjs +438 -527
- package/pretty.mjs +100 -23
- package/repl.mjs +124 -86
- package/run.mjs +13 -16
- package/symbol-table.mjs +44 -41
- package/test-filters.mjs +3 -3
- package/typing-test.mjs +40 -0
- package/typing.mjs +689 -0
- package/INTRO.md +0 -88
- package/TODO.md +0 -54
- package/bug.json +0 -419
- package/chatGPT.md +0 -235
- package/chatGPT.md~ +0 -119
- package/code-resolution.md +0 -121
- package/code-resolution.mjs +0 -51
- package/filters.mjs +0 -59
package/BIG_PICTURE.md
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# Big Picture
|
|
1
2
|
|
|
2
3
|
`Kernel-code` is an experiment aiming to define a "perfect programming language".
|
|
3
4
|
|
|
@@ -22,7 +23,7 @@ Types are defined by two constructs:
|
|
|
22
23
|
1. Product
|
|
23
24
|
2. Union (also called tagged or disjoint union)
|
|
24
25
|
|
|
25
|
-
Given a
|
|
26
|
+
Given a finite (possibly empty) set of types `t1, t2, ..., tn` and a set of pairwise different tags (labels) `l1, l2, ..., ln`,
|
|
26
27
|
|
|
27
28
|
- by `{ t1 l1, t2 l2, ..., tn ln }`, we define a _product type_ with exactly `n` projection functions `.l1`, `.l2`, `...`, `.ln`,
|
|
28
29
|
mapping a value of type `{t1 l1, t2 l2, ..., tn ln}` into a value of type `t1`, `t2`, `...`, `tn`, respectively.
|
|
@@ -42,7 +43,6 @@ Some properties of these types:
|
|
|
42
43
|
as a union type value (a variant).
|
|
43
44
|
2. The empty product type `{}` has a single value, called the _unit_ and also denoted by `{}`, which has no fields.
|
|
44
45
|
3. The empty union type `<>` has no values.
|
|
45
|
-
4. The product and union types form dual categories.
|
|
46
46
|
|
|
47
47
|
### Partial functions
|
|
48
48
|
|
|
@@ -64,7 +64,7 @@ empty composition, `()`, defines the identity function.
|
|
|
64
64
|
|
|
65
65
|
### Program
|
|
66
66
|
|
|
67
|
-
A `kernel-core` program is a set of definitions of types and partial functions followed by an _expression_,
|
|
67
|
+
A `kernel-core` program is a set of definitions of types and partial functions, followed by an _expression_,
|
|
68
68
|
which is the partial function the program defines.
|
|
69
69
|
|
|
70
70
|
The language syntax is defined by:
|
|
@@ -97,7 +97,7 @@ The `typing` expression acts as a type annotation and can be seen as a 'filter',
|
|
|
97
97
|
function defined only for the values of the corresponding type.
|
|
98
98
|
|
|
99
99
|
That's it.
|
|
100
|
-
No `
|
|
100
|
+
No `builtin` types, no `if` statement, no `loop`, no `throw`, no _closure_, no _annotations_, and no macros.
|
|
101
101
|
Just types and partial functions.
|
|
102
102
|
|
|
103
103
|
### Normalization
|
|
@@ -170,41 +170,59 @@ Functions `bit0`, `bit1`, and `zero` are "constant polymorphic functions", meani
|
|
|
170
170
|
|
|
171
171
|
- constant: if defined, they always return exactly the same value;
|
|
172
172
|
- polymorphic: they are defined for more than one pair of input and output type: functions
|
|
173
|
-
`
|
|
174
|
-
denotes an unconstrained type pattern
|
|
173
|
+
`bit0` and `bit1` are of type `?X -> $bit`, and `zero` is of type `?X -> $byte`, where `?X`
|
|
174
|
+
denotes an unconstrained type pattern, also denoted as `?(...)`.
|
|
175
175
|
|
|
176
176
|
Functions `inc` and `inc3` are (non-polymorphic) functions of types
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
`$byte -> ${ bit overflown, byte byte }` and
|
|
178
|
+
`${ bit overflown, byte byte } -> ${ bit overflown, byte byte }`, respectively.
|
|
179
179
|
|
|
180
|
-
Function `inc_o` is a polymorphic function of type patterns:
|
|
181
|
-
following constraints:
|
|
180
|
+
Function `inc_o` is a polymorphic function of type patterns: `?X -> ${ byte byte, bit overflown }`
|
|
181
|
+
with following constraints:
|
|
182
182
|
|
|
183
|
-
-
|
|
184
|
-
> `?
|
|
185
|
-
-
|
|
183
|
+
- `?X` is a product or union type with at least two fields: `byte` and `overflown`, denoted by:
|
|
184
|
+
> `?( $byte byte, Z overflown, ...)`;
|
|
185
|
+
- `?Z` is a type (union or product) with field `i` denoted by:
|
|
186
186
|
> `?( V i, ...)`;
|
|
187
|
-
- `V` is unconstrained
|
|
188
|
-
- `Y` is a product type with exactly two fields: `byte` and `overflown`, denoted by:
|
|
189
|
-
> `?{ byte byte, bit overflown }`;
|
|
187
|
+
- `V` is unconstrained, denoted by `(...)`;
|
|
190
188
|
|
|
191
|
-
|
|
192
|
-
whereas the other type patterns are not.
|
|
189
|
+
We could write it as: `?($byte byte, ((...) i, ...) overflown, ...)`.
|
|
193
190
|
|
|
194
|
-
|
|
191
|
+
The target type `${ byte byte, bit overflown }` was derived from pattern `?{ $byte byte, $bit overflown }`.
|
|
192
|
+
Such a pettern is called _singleton pattern_ as only one type fits the pattern.
|
|
195
193
|
|
|
196
194
|
## Universal Schema Registry
|
|
197
195
|
|
|
198
|
-
Since the normalization process for types is fast and deterministic, we can build a universal
|
|
196
|
+
Since the normalization process for types is fast and deterministic, we can build a universal
|
|
197
|
+
schema registry that will store all invented types.
|
|
198
|
+
The registry will be a key-value store, where the key is the hash of the normalized type,
|
|
199
|
+
and the value is the normalized type itself.
|
|
199
200
|
|
|
200
|
-
All functions (non-polymorphic and polymorphic) will be renamed by the hash of their normalized
|
|
201
|
-
|
|
202
|
-
Non-polymorphic functions can be easily indexed by the hashes of their input and output types so that we can quickly find the function we need, e.g., for autocomplition. Searching for polymorphic functions is more complicated, as we need to find the function whose input and output type patterns fit given types.
|
|
201
|
+
All functions (non-polymorphic and polymorphic) will be renamed by the hash of their normalized
|
|
202
|
+
definition and stored in the similar key-value store.
|
|
203
203
|
|
|
204
|
+
Non-polymorphic functions can be easily indexed by the hashes of their input and output types
|
|
205
|
+
so that we can quickly find the function we need.
|
|
206
|
+
Searching for polymorphic functions is more complicated, as we need to find the function
|
|
207
|
+
whose input and output type patterns fit given types.
|
|
204
208
|
|
|
205
209
|
## Serialization and Compilation
|
|
206
210
|
|
|
207
|
-
The language is designed to transform _codes_, i.e., serialized typed values, i.e., trees
|
|
211
|
+
The language is designed to transform _codes_, i.e., serialized typed values, i.e., trees
|
|
212
|
+
accepted by a tree automaton, into other _codes_.
|
|
213
|
+
The transformation is done by partial functions as defined in the language.
|
|
214
|
+
The non-recursive and tail-recursive (and even some non-tail recursive) functions can
|
|
215
|
+
be compiled into deterministic finite (pushdown) transducers.
|
|
216
|
+
|
|
217
|
+
### AND-OR graphs for enconding and decoding codes
|
|
218
|
+
|
|
219
|
+
This could be generic and compact way to encode and decode typed values.
|
|
220
|
+
The idea is to use _prefix codes_ (a class of languages such that no word is a prefix of
|
|
221
|
+
another word) to encode the values.
|
|
222
|
+
|
|
223
|
+
### RUST data structures
|
|
224
|
+
|
|
225
|
+
A type can be translated into a Rust data structure, and a function can be translated into a Rust function.
|
|
208
226
|
|
|
209
227
|
## Linking with Other Languages
|
|
210
228
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { t, in_out } from './index.mjs';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import assert from 'assert';
|
|
4
|
+
|
|
5
|
+
// t(fs.readFileSync("./Examples/blowup.k").toString("utf8"), (annotated) => {
|
|
6
|
+
// // console.log(JSON.stringify(annotated,null,2));
|
|
7
|
+
// const {input,output} = in_out(annotated);
|
|
8
|
+
// console.log(input);
|
|
9
|
+
// console.log(output);
|
|
10
|
+
// assert.equal(output.pattern, '<...>');
|
|
11
|
+
// assert.equal(input.pattern, '(...)');
|
|
12
|
+
// console.log("OK");
|
|
13
|
+
// });
|
|
14
|
+
|
|
15
|
+
t(`
|
|
16
|
+
B = {{} u} A;
|
|
17
|
+
A = < .a, .b A, .c {() z} A, B >;
|
|
18
|
+
A
|
|
19
|
+
`, (annotated) => {
|
|
20
|
+
// console.log(JSON.stringify(annotated,null,2));
|
|
21
|
+
const {input,output} = in_out(annotated);
|
|
22
|
+
console.log(input);
|
|
23
|
+
console.log(output);
|
|
24
|
+
assert.equal(output.type, annotated.representatives["bnat"]);
|
|
25
|
+
assert.equal(input.type, annotated.representatives["pair"]);
|
|
26
|
+
console.log("OK");
|
|
27
|
+
});
|
|
@@ -3,8 +3,10 @@ import fs from 'node:fs';
|
|
|
3
3
|
import assert from 'assert';
|
|
4
4
|
|
|
5
5
|
t(fs.readFileSync("./Examples/bnat-patterns.k").toString("utf8"), (annotated) => {
|
|
6
|
+
// console.log(JSON.stringify(annotated,null,2));
|
|
6
7
|
const {input,output} = in_out(annotated);
|
|
7
|
-
|
|
8
|
-
assert.equal(
|
|
8
|
+
// console.log(output);
|
|
9
|
+
assert.equal(output.type, annotated.representatives["bnat"]);
|
|
10
|
+
assert.equal(input.type, annotated.representatives["pair"]);
|
|
9
11
|
console.log("OK");
|
|
10
12
|
});
|
|
@@ -9,7 +9,32 @@ $b {1 one, () two, () c} .one
|
|
|
9
9
|
|
|
10
10
|
`, (annotated) => {
|
|
11
11
|
const {input,output} = in_out(annotated);
|
|
12
|
-
|
|
13
|
-
assert.equal(
|
|
12
|
+
// console.log({input,output});
|
|
13
|
+
assert.equal(input.type, annotated.representatives["b"]);
|
|
14
|
+
assert.equal(output.type, "int");
|
|
14
15
|
console.log("OK");
|
|
15
|
-
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
t(`
|
|
19
|
+
$a = < int true, bool false > ;
|
|
20
|
+
$a .true
|
|
21
|
+
`, (annotated) => {
|
|
22
|
+
const {input,output} = in_out(annotated);
|
|
23
|
+
console.log({input,output});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
t(`
|
|
27
|
+
x = .x;
|
|
28
|
+
xy = x.y;
|
|
29
|
+
f = {
|
|
30
|
+
{ {5 y} x} xy i,
|
|
31
|
+
{ {true y} x} xy b
|
|
32
|
+
};
|
|
33
|
+
f .b
|
|
34
|
+
`, (annotated) => {
|
|
35
|
+
const {input,output} = in_out(annotated);
|
|
36
|
+
console.log({input,output});
|
|
37
|
+
assert.equal(input.pattern, '(...)');
|
|
38
|
+
assert.equal(output.type, "bool");
|
|
39
|
+
console.log("OK");
|
|
40
|
+
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { annotate } from "../index.mjs";
|
|
2
2
|
|
|
3
3
|
function in_out(annotated) {
|
|
4
|
-
const [input,output] = annotated.rels.__main__
|
|
5
|
-
annotated.
|
|
4
|
+
const [input,output] = annotated.rels.__main__.def.patterns.map( (pat) =>
|
|
5
|
+
annotated.rels.__main__.typePatternGraph.get_pattern(pat)
|
|
6
6
|
);
|
|
7
7
|
return { input, output };
|
|
8
8
|
}
|
|
@@ -4,7 +4,7 @@ import assert from 'assert';
|
|
|
4
4
|
|
|
5
5
|
t(fs.readFileSync("./Examples/nat.k").toString("utf8"), (annotated) => {
|
|
6
6
|
const {input,output} = in_out(annotated);
|
|
7
|
-
assert.equal(output.
|
|
8
|
-
assert.equal(input.
|
|
7
|
+
assert.equal(output.type, annotated.representatives["nat"]);
|
|
8
|
+
assert.equal(input.type, annotated.representatives["nat"]);
|
|
9
9
|
console.log("OK");
|
|
10
10
|
});
|
|
@@ -8,7 +8,7 @@ t(`$b = < {} true, {} false > ;
|
|
|
8
8
|
not not
|
|
9
9
|
`, (annotated) => {
|
|
10
10
|
const {input,output} = in_out(annotated);
|
|
11
|
-
assert.equal(input.
|
|
12
|
-
assert.equal(output.
|
|
11
|
+
assert.equal(input.type, annotated.representatives["b"]);
|
|
12
|
+
assert.equal(output.type, annotated.representatives["b"]);
|
|
13
13
|
console.log("OK");
|
|
14
14
|
});
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { t, in_out } from './index.mjs';
|
|
2
2
|
import assert from 'assert';
|
|
3
|
+
import hash from "../hash.mjs";
|
|
4
|
+
|
|
5
|
+
const unitCode = hash('$C0={};');
|
|
3
6
|
|
|
4
7
|
t('{}', (annotated) => {
|
|
5
8
|
const {input,output} = in_out(annotated);
|
|
6
|
-
assert.equal(input.
|
|
7
|
-
assert.equal(output.
|
|
9
|
+
assert.equal(input.pattern, '(...)');
|
|
10
|
+
assert.equal(output.type, unitCode);
|
|
8
11
|
console.log("OK");
|
|
9
12
|
});
|
|
10
13
|
|
|
@@ -12,10 +15,11 @@ t(`
|
|
|
12
15
|
$b = < {} true, {} false > ;
|
|
13
16
|
$pair = { b one, b two } ;
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
{() one, () two} $pair
|
|
16
19
|
`, (annotated) => {
|
|
17
20
|
const {input,output} = in_out(annotated);
|
|
18
|
-
|
|
19
|
-
assert.equal(
|
|
21
|
+
|
|
22
|
+
assert.equal(input.type, annotated.representatives["b"]);
|
|
23
|
+
assert.equal(output.type, annotated.representatives["pair"]);
|
|
20
24
|
console.log("OK");
|
|
21
25
|
});
|
|
@@ -8,7 +8,7 @@ t(`
|
|
|
8
8
|
rlz
|
|
9
9
|
`, (annotated) => {
|
|
10
10
|
const {input,output} = in_out(annotated);
|
|
11
|
-
assert.equal(output.
|
|
12
|
-
assert.equal(input.
|
|
11
|
+
assert.equal(output.type, annotated.representatives["nat"]);
|
|
12
|
+
assert.equal(input.type, annotated.representatives["nat"]);
|
|
13
13
|
console.log("OK");
|
|
14
14
|
});
|
|
@@ -3,26 +3,17 @@ import assert from 'assert';
|
|
|
3
3
|
|
|
4
4
|
t('[]', (annotated) => {
|
|
5
5
|
const {input,output} = in_out(annotated);
|
|
6
|
-
assert.equal(input.
|
|
7
|
-
assert.equal(output.
|
|
6
|
+
assert.equal(input.pattern, '(...)');
|
|
7
|
+
assert.equal(output.pattern, "[]");
|
|
8
8
|
console.log("OK");
|
|
9
9
|
});
|
|
10
10
|
|
|
11
|
-
t(
|
|
11
|
+
t("$int [ $int true, false ] .0", (annotated) => {
|
|
12
12
|
const {input,output} = in_out(annotated);
|
|
13
|
-
assert.equal(input.
|
|
14
|
-
assert.equal(output.type, "
|
|
13
|
+
assert.equal(input.type, "int");
|
|
14
|
+
assert.equal(output.type, "bool");
|
|
15
15
|
console.log("OK");
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
t(`$int [ $int true,
|
|
19
|
-
|
|
20
|
-
assert.equal(input.code, "int");
|
|
21
|
-
assert.equal(output.code, "bool");
|
|
22
|
-
console.log("OK");
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
// assert.throws(() => t(`$int [ $int true, 12 ]`), /Error/);
|
|
26
|
-
// console.log("OK");
|
|
27
|
-
|
|
28
|
-
// t(`[]`);
|
|
18
|
+
assert.throws(() => t(`$int [ $int true, 12 ]`), /Error/);
|
|
19
|
+
console.log("OK");
|
package/Filters/bug.k
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
remap = ?T {.x y} ?T ?<X z, ...>;
|
|
2
|
+
swap = ?T {.x y, .y x} ?T;
|
|
3
|
+
|
|
4
|
+
$t = <int x, int y>;
|
|
5
|
+
|
|
6
|
+
$t2 = <int x, int y, int z>;
|
|
7
|
+
|
|
8
|
+
-- {12 x} $t remap $t
|
|
9
|
+
-- {[1,2] x} remap
|
|
10
|
+
-- {"ala" x, 3 y} swap
|
|
11
|
+
|
|
12
|
+
{
|
|
13
|
+
{12 x} $t2 remap $t2 remap,
|
|
14
|
+
{"ala" x, "ola" y} swap
|
|
15
|
+
}
|
package/Filters/filter.k
ADDED
package/Graph.mjs
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
class Graph {
|
|
2
|
+
constructor(edges, vertices = {}) {
|
|
3
|
+
this.edges = edges;
|
|
4
|
+
this.vertices = vertices;
|
|
5
|
+
for (const dir of ['src', 'dst']) {
|
|
6
|
+
this[dir] = {};
|
|
7
|
+
for (let i=0; i < edges.length; i++) {
|
|
8
|
+
const e = edges[i];
|
|
9
|
+
if (vertices[e[dir]] == undefined) {
|
|
10
|
+
vertices[e[dir]] = {
|
|
11
|
+
_rem: "discovered"
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
if (this[dir][e[dir]] == null) {
|
|
15
|
+
this[dir][e[dir]] = [];
|
|
16
|
+
}
|
|
17
|
+
this[dir][e[dir]].push(i);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function sccs(graph) {
|
|
24
|
+
const stack = [];
|
|
25
|
+
const disc = {};
|
|
26
|
+
const low = {};
|
|
27
|
+
const inStack = {};
|
|
28
|
+
const sccs = [];
|
|
29
|
+
let time = 0;
|
|
30
|
+
|
|
31
|
+
const dfs = (u) => {
|
|
32
|
+
disc[u] = low[u] = time++;
|
|
33
|
+
stack.push(u);
|
|
34
|
+
inStack[u] = true;
|
|
35
|
+
|
|
36
|
+
for (const e of graph.src[u] || []) {
|
|
37
|
+
const v = graph.edges[e].dst;
|
|
38
|
+
if (disc[v] == undefined) {
|
|
39
|
+
dfs(v);
|
|
40
|
+
low[u] = Math.min(low[u], low[v]);
|
|
41
|
+
} else if (inStack[v]) {
|
|
42
|
+
low[u] = Math.min(low[u], disc[v]);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (low[u] === disc[u]) {
|
|
47
|
+
const scc = [];
|
|
48
|
+
let w;
|
|
49
|
+
do {
|
|
50
|
+
w = stack.pop();
|
|
51
|
+
inStack[w] = false;
|
|
52
|
+
scc.push(w);
|
|
53
|
+
} while (w !== u);
|
|
54
|
+
sccs.push(scc);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
for (const x in graph.vertices) {
|
|
59
|
+
if (disc[x] == undefined) {
|
|
60
|
+
dfs(x);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return sccs;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
function topoOrder(graph){
|
|
67
|
+
const starts = [];
|
|
68
|
+
const result = [];
|
|
69
|
+
const inDegree = {};
|
|
70
|
+
for (const v in graph.vertices) {
|
|
71
|
+
const degree = graph.dst[v]?.length || 0;
|
|
72
|
+
if (degree == 0) {
|
|
73
|
+
starts.push(v);
|
|
74
|
+
} else {
|
|
75
|
+
inDegree[v] = degree;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let x;
|
|
80
|
+
while (x = starts.pop()) {
|
|
81
|
+
result.push(x);
|
|
82
|
+
const outs = graph.src[x] || [];
|
|
83
|
+
for (const e of outs) {
|
|
84
|
+
const y = graph.edges[e].dst;
|
|
85
|
+
inDegree[y]--;
|
|
86
|
+
if (inDegree[y] == 0) {
|
|
87
|
+
starts.push(y);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export { Graph, sccs, topoOrder };
|
|
95
|
+
export default { Graph, sccs, topoOrder };
|
package/README.md
CHANGED
|
@@ -87,7 +87,7 @@ supported.
|
|
|
87
87
|
|
|
88
88
|
### Basic extensions
|
|
89
89
|
|
|
90
|
-
#### Constants, i.e., literals for `
|
|
90
|
+
#### Constants, i.e., literals for `string`, `int`, `bool`, and `null`
|
|
91
91
|
|
|
92
92
|
A constant defines a function which ignores its argument and produces
|
|
93
93
|
the constant value. E.g.:
|
|
@@ -95,7 +95,7 @@ the constant value. E.g.:
|
|
|
95
95
|
{123 int, "kScript" str, true bool, null null} :
|
|
96
96
|
"any" --> {"int":123,"str":"kScript","bool":true,"null":null}
|
|
97
97
|
|
|
98
|
-
Those values, i.e.,
|
|
98
|
+
Those values, i.e., _strings_, _integers_, _booleans_, and _null_, admit the
|
|
99
99
|
projection to the canonicat string representation of the value, e.g.:
|
|
100
100
|
|
|
101
101
|
.2 :
|
|
@@ -176,7 +176,6 @@ is not supported in _code derivation_ (explained below).
|
|
|
176
176
|
"2.12" --> 2.12
|
|
177
177
|
"[1,2.11,0.3e-32]" --> [1,2.11,3e-33]
|
|
178
178
|
|
|
179
|
-
|
|
180
179
|
- other predefined parial functions are: `DIV`, `FDIV`, `CONS`,
|
|
181
180
|
`SNOC`, `toDateMsec`, `toDateStr`, and `_log!`.
|
|
182
181
|
|
|
@@ -185,10 +184,11 @@ is not supported in _code derivation_ (explained below).
|
|
|
185
184
|
### Function and code (i.e., _type_) definitions
|
|
186
185
|
|
|
187
186
|
dec = [(),-1] PLUS;
|
|
188
|
-
max = <SNOC [.
|
|
187
|
+
max = <SNOC [.car, .cdr max] <GT.0, .1>, .0> ;
|
|
189
188
|
factorial = < [(),0] GT .0 [dec factorial, ()] TIMES, 1 >;
|
|
190
189
|
|
|
191
|
-
### Codes (schemas, i.e.,
|
|
190
|
+
### Codes (schemas, i.e., _types_)
|
|
191
|
+
|
|
192
192
|
_Codes_ (prefixed by `$`) can be defined by tagged union and product. E.g.:
|
|
193
193
|
|
|
194
194
|
|
|
@@ -256,12 +256,15 @@ fail, indicating that the script is invalid. In some other cases the
|
|
|
256
256
|
code derivation can succeed even to the point of reducig every pattern
|
|
257
257
|
to a single code making the program fully annotated by codes.
|
|
258
258
|
|
|
259
|
-
|
|
260
|
-
|
|
259
|
+
The language `k` supports _type patterns_, which is used for type inference, however the patterns are not concidered in the evaluation of the program.
|
|
260
|
+
|
|
261
|
+
```k
|
|
262
|
+
tree_pattern = ?<(...) leaf, {T left, T right} tree> = T;
|
|
263
|
+
```
|
|
261
264
|
|
|
262
265
|
---
|
|
263
266
|
|
|
264
|
-
### List comprehension
|
|
267
|
+
### List comprehension
|
|
265
268
|
|
|
266
269
|
A vector can be "open" by PIPE (`|`) operator so the following partial function is applied to
|
|
267
270
|
each element of the vector one by one, yielding another open value. An open value can be "closed",
|
|
@@ -355,11 +358,11 @@ times value `x` appears in the list. (see `Examples/list-comprehension.k` for a
|
|
|
355
358
|
Another example could be finding the biggest (max) value in a vector:
|
|
356
359
|
|
|
357
360
|
max = <
|
|
358
|
-
SNOC
|
|
359
|
-
[.
|
|
360
|
-
<GT .0, .1>
|
|
361
|
-
,
|
|
362
|
-
.0
|
|
361
|
+
SNOC # [x0, x1, x2, ...] --> {x0 car, [x1, x2, ...] cdr}
|
|
362
|
+
[.car, .cdr max] # [x0, [x1, x2, ...]] --> [x0, max(x1,x2,...)], i.e., recursive call
|
|
363
|
+
<GT .0, .1> # if x0 > max(x1,x2,...) then x0 else max(x1,x2,...)
|
|
364
|
+
, # when SNOC is not defined, i.e., if the input vector has one element:
|
|
365
|
+
.0 # [x0] --> x0
|
|
363
366
|
>;
|
|
364
367
|
max
|
|
365
368
|
|
|
@@ -468,10 +471,10 @@ For example:
|
|
|
468
471
|
|
|
469
472
|
1.
|
|
470
473
|
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | jq '.'
|
|
471
|
-
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | k
|
|
474
|
+
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | k '()' -1
|
|
472
475
|
2.
|
|
473
476
|
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | jq '.[0]'
|
|
474
|
-
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | k
|
|
477
|
+
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | k '.0' -1
|
|
475
478
|
3.
|
|
476
479
|
jq '.[0] | {message: .commit.message, name: .commit.committer.name}'
|
|
477
480
|
k '.0 {.commit.message message, .commit.committer.name name}' -1
|