@fraczak/k 2.1.6 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/BIG_PICTURE.md ADDED
@@ -0,0 +1,211 @@
1
+
2
+ `Kernel-code` is an experiment aiming to define a "perfect programming language".
3
+
4
+ ## Basics
5
+
6
+ The language describes "partial first-order functions" on "printable" values.
7
+ The printable values can be seen as rooted, edge-labeled trees, intuitively similar to an
8
+ XML or a JSON document. The values are always typed.
9
+
10
+ ### Types (codes)
11
+
12
+ Formally, a _type_ is a (subclass of) finite tree automata. The type defines a set of its values,
13
+ which corresponds to the set of trees accepted by the automaton.
14
+ Therefore, every type admits a unique normal form in terms of its minimal deterministic tree automaton.
15
+
16
+ The set of all types can be seen as the universal deterministic (infinite) tree automaton.
17
+ Every node of that automaton defines a type; only a finite set of nodes are reachable from
18
+ any node.
19
+
20
+ Types are defined by two constructs:
21
+
22
+ 1. Product
23
+ 2. Union (also called tagged or disjoint union)
24
+
25
+ Given a set (possibly empty) of types `t1, t2, ..., tn` and a set of pairwise different tags (labels) `l1, l2, ..., ln`,
26
+
27
+ - by `{ t1 l1, t2 l2, ..., tn ln }`, we define a _product type_ with exactly `n` projection functions `.l1`, `.l2`, `...`, `.ln`,
28
+ mapping a value of type `{t1 l1, t2 l2, ..., tn ln}` into a value of type `t1`, `t2`, `...`, `tn`, respectively.
29
+ - by `< t1 l1, t2 l2, ..., tn ln >`, we define a _union type_ with exactly `n` projection functions `.l1`, `.l2`, `...`, `.ln`,
30
+ mapping a value of type `<t1 l1, t2 l2, ..., tn ln>` into a value of type `t1`, `t2`, `...`, `tn`, respectively.
31
+
32
+ Intuitively, the projection functions on a product type are all total (meaning, they are defined for every value of the
33
+ input product type), whereas in the case of a union type, exactly one projection function is defined
34
+ for a given value of the union type.
35
+
36
+ Some properties of these types:
37
+
38
+ 1. Singleton product and singleton union types, `{ t label }` and `< t label >`, are equivalent as they have
39
+ the same set of values (and the same projection function `.label`). That's why, we not allow singleton product nor
40
+ singleton union types in the syntax of the language. The other benefit is that we will be able to use the same systax
41
+ for values of both product and union types, interpretting every singleton product-like value, e.g., `{ a_value label }`,
42
+ as a union type value (a variant).
43
+ 2. The empty product type `{}` has a single value, called the _unit_ and also denoted by `{}`, which has no fields.
44
+ 3. The empty union type `<>` has no values.
45
+ 4. The product and union types form dual categories.
46
+
47
+ ### Partial functions
48
+
49
+ A _partial function_ is a function that is not defined for every value of its domain.
50
+
51
+ There are three ways of combining partial functions:
52
+
53
+ 1. __Composition__: we write a composition of `f` and `g` as `(f g)`, meaning that if `f` is defined on valye `x` producing `y`,
54
+ and `g` is defined on value `y` producing `z`, then `(f g)` is defined on value `x` producing `z`.
55
+ 2. __Union__: we write `< f1, f2 >` for a union of two functions `f1` and `f2`, meaning that
56
+ if `f1` is defined on value `x` producing `y`, then `< f1, f2 >`
57
+ is defined on value `x` producing `y`. Otherwise, i.e., when `f1` is not defined for `x`, `< f1 f2 >` acts as `f2`.
58
+ 3. __Product__: we write `{f1 lab1, f2 lab2 }` for a product of two functions `f1` and `f2`, meaning that if `f1` and `f2`
59
+ are both defined on value `x` producing `y1` and `y2`, respectively, then `{f1 lab1, f2 lab2 }`
60
+ is defined on value `x` producing `{y1 lab1, y2 lab2}`. Otherwise, `{f1 lab1, f2 lab2 }` is not defined for `x`.
61
+
62
+ Actually, all of the above operations take any number of arguments, not only two. For example,
63
+ empty composition, `()`, defines the identity function.
64
+
65
+ ### Program
66
+
67
+ A `kernel-core` program is a set of definitions of types and partial functions followed by an _expression_,
68
+ which is the partial function the program defines.
69
+
70
+ The language syntax is defined by:
71
+
72
+ ```bnf
73
+ program ::= (type_definition | function_definition) * expression
74
+
75
+ type_definition ::= '$' type_name '=' type ';'
76
+ type ::= '{' type_label_list '}' | '<' type_label_list '>'
77
+ type_label_list ::= /* empty */ | ( type_expression label_name ',' ) + type_expression label_name
78
+ type_expression ::= type_name | type
79
+
80
+ function_definition ::= function_name '=' expression ';'
81
+ expression ::= projection | typing | composition | union | product | function_name
82
+ projection ::= '.' label_name
83
+ typing ::= '$' tape_expression
84
+ composition ::= '(' expression * ')'
85
+ union ::= '<' (expression ',') + expression '>'
86
+ product ::= '{' expression_label_list '}'
87
+ expression_label_list ::= /* empty */ | ( expression label_name ',' ) * expression label
88
+ ```
89
+
90
+ We assume that the `type_name`, `function_name`, and `label_name` are identifiers (strings) such that:
91
+
92
+ 1. All defined type names are distinct.
93
+ 2. All defined function names are distinct.
94
+ 3. All label names within a type definition or a `product` expression are locally distinct.
95
+
96
+ The `typing` expression acts as a type annotation and can be seen as a 'filter', i.e., an identity
97
+ function defined only for the values of the corresponding type.
98
+
99
+ That's it.
100
+ No `int`, no `if` statement, no `loop`, no `throw`, no _closure_, no _annotations_, and no macros.
101
+ Just types and partial functions.
102
+
103
+ ### Normalization
104
+
105
+ All type names are replaced by the hash of their canonical representation.
106
+
107
+ We will also replace the function name by the hash of the normalized unfolded definition of the function.
108
+ Obviously, two different definitions of the same function may have different hashes.
109
+
110
+ This approach solves the problem of modules and imports and opens the door to a universal
111
+ registry of types (schemas) and functions.
112
+
113
+ ## Typing and Polymorphism (codes and filters/patterns)
114
+
115
+ Abstract Syntax Tree of a program after parsing consists of a dictionary of _type definitions_,
116
+ a dictionary of _function definitions_, and the final _main expression_.
117
+
118
+ In principle, the initial form of the Abstract Syntax Tree, _raw_ AST, is enough to evaluate
119
+ the program on an input.
120
+
121
+ Our objective however is to compute canonicals representations for types and normalized
122
+ representations for functions, so they could be effectively reused.
123
+
124
+ The normalization steps are:
125
+
126
+ 1. Build the _type graph_ from all types used by the program, i.e., used in _type definitions_
127
+ as well as type expressions used in _function definitions_ and the _main expression_.
128
+ 2. Annotate the expressions with types or type patterns; every node of the AST is annotated with a pair of type patterns.
129
+ 3. Turn the _singleton_ type patterns into types and add them to the _type graph_. Go to (2) unless no change.
130
+ 4. Normalize the function definitions by rewriting them as the fix-point of a single equation.
131
+
132
+ ### Example
133
+
134
+ ```k
135
+ $ bit = < {} o, {} i >;
136
+ bit0 = {{} o} $bit;
137
+ bit1 = {{} i} $bit;
138
+
139
+ $ byte = { bit b0, bit b1, bit b2, bit b3 };
140
+ zero = bit0 { () b0, () b1, () b2, () b3 } $byte;
141
+
142
+ inc = $byte
143
+ <
144
+ { .b0.o bit0 overflown, {bit1 b0, .b1 b1, .b2 b2, .b3 b3 } byte },
145
+ { .b1.o bit0 overflown, {bit0 b0, bit1 b1, .b2 b2, .b3 b3 } byte },
146
+ { .b2.o bit0 overflown, {bit0 b0, bit0 b1, bit1 b2, .b3 b3 } byte },
147
+ { .b3.o bit0 overflown, {bit0 b0, bit0 b1, bit0 b2, bit1 b3 } byte },
148
+ { bit1 overflown, zero byte }
149
+ >
150
+ ;
151
+
152
+ -- inc with overflown flag (polymorphism)
153
+ inc_o =
154
+ { .byte inc inc, .overflown overflown }
155
+ {
156
+ .inc.byte byte,
157
+ <.overflown.i bit1, .inc.overflown > overflown
158
+ }
159
+ ;
160
+
161
+ inc3 = inc inc_o inc_o;
162
+
163
+ inc3
164
+ ```
165
+
166
+ In the above program, we define a type `bit` a union of two unit types,
167
+ and a type `byte` as a product, for simplicity, of four `bit`s.
168
+
169
+ Functions `bit0`, `bit1`, and `zero` are "constant polymorphic functions", meaning:
170
+
171
+ - constant: if defined, they always return exactly the same value;
172
+ - polymorphic: they are defined for more than one pair of input and output type: functions
173
+ `bit1` and `bit2` are of type `X -> bit`, and `zero` is of type `X -> byte`, where `X`
174
+ denotes an unconstrained type pattern.
175
+
176
+ Functions `inc` and `inc3` are (non-polymorphic) functions of types
177
+ `byte -> { bit overflown, byte byte }` and
178
+ `{ bit overflown, byte byte } -> { bit overflown, byte byte }`, respectively.
179
+
180
+ Function `inc_o` is a polymorphic function of type patterns: `X -> Y` with
181
+ following constraints:
182
+
183
+ - `X` is a product 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
+ > `?( 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 }`;
190
+
191
+ The type pattern for `Y` is _singleton_, as only one type fits the pattern,
192
+ whereas the other type patterns are not.
193
+
194
+ In this example, we were able to find the most general type pattern for all sub-expressions of the program. However, we still do not have a way to find the most general type patterns in the general case. This is work in progress.
195
+
196
+ ## Universal Schema Registry
197
+
198
+ Since the normalization process for types is fast and deterministic, we can build a universal schema registry that will store all invented types. The registry will be a key-value store, where the key is the hash of the normalized type, and the value is the normalized type itself.
199
+
200
+ All functions (non-polymorphic and polymorphic) will be renamed by the hash of their normalized definition and stored in the similar key-value store.
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.
203
+
204
+
205
+ ## Serialization and Compilation
206
+
207
+ The language is designed to transform _codes_, i.e., serialized typed values, i.e., trees accepted by a tree automaton, into other _codes_. The transformation is done by partial functions as defined in the language. The non-recursive and tail-recursive (and even some non-tail recursive) functions can be compiled into deterministic finite (pushdown) transducers.
208
+
209
+ ## Linking with Other Languages
210
+
211
+ ## Streams and Arrays (Map-Reduce)
@@ -0,0 +1,10 @@
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/bnat-patterns.k").toString("utf8"), (annotated) => {
6
+ const {input,output} = in_out(annotated);
7
+ assert.equal(output.code, annotated.representatives["bnat"]);
8
+ assert.equal(input.code, annotated.representatives["pair"]);
9
+ console.log("OK");
10
+ });
@@ -0,0 +1,19 @@
1
+ import { t, in_out } from './index.mjs';
2
+ import assert from 'assert';
3
+
4
+ function is_result_code(code) {
5
+ return function(annotated) {
6
+ const {output} = in_out(annotated);
7
+ assert.strictEqual(output.code, code);
8
+ console.log('OK');
9
+ }
10
+ }
11
+
12
+ t('true', is_result_code('bool'));
13
+ t('false $bool', is_result_code('bool'));
14
+ t('1', is_result_code('int'));
15
+ t('12 $int', is_result_code('int'));
16
+ t('"ala"', is_result_code('string'));
17
+ t('"a" $string', is_result_code('string'));
18
+
19
+ t('${} true $bool 1 $int "a" $string', is_result_code('string'));
@@ -0,0 +1,15 @@
1
+ import { t, in_out } from './index.mjs';
2
+ import assert from 'assert';
3
+
4
+ t(`
5
+ $b = < {} true, {} false > ;
6
+ $pair = { b one, b two } ;
7
+
8
+ $b {1 one, () two, () c} .one
9
+
10
+ `, (annotated) => {
11
+ const {input,output} = in_out(annotated);
12
+ assert.equal(input.code, annotated.representatives["b"]);
13
+ assert.equal(output.code, "int");
14
+ console.log("OK");
15
+ });
@@ -0,0 +1,20 @@
1
+ import { annotate } from "../index.mjs";
2
+
3
+ function in_out(annotated) {
4
+ const [input,output] = annotated.rels.__main__[0].patterns.map( (pat) =>
5
+ annotated.patternNodes[pat]
6
+ );
7
+ return { input, output };
8
+ }
9
+
10
+
11
+ function t(script, cb = (annotated) => console.log(in_out(annotated))) {
12
+ // console.log("--- Testing Code Derivation ---");
13
+ const annotated = annotate(script);
14
+ // console.log(JSON.stringify(annotated, "", 2));
15
+ return cb(annotated);
16
+ }
17
+
18
+ export default { t, in_out };
19
+ export { t, in_out };
20
+
@@ -0,0 +1,11 @@
1
+ import { t, in_out } from './index.mjs';
2
+ import assert from 'assert';
3
+
4
+ t(` < .a, () > `, (annotated) => {
5
+ const {input,output} = in_out(annotated);
6
+ assert.equal(input.type, "union");
7
+ assert.equal(output, input);
8
+ console.log("OK");
9
+ });
10
+
11
+ // Notice that the following are equivalent: '<(), .a>', '<()>', and '()';
@@ -0,0 +1,10 @@
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/nat.k").toString("utf8"), (annotated) => {
6
+ const {input,output} = in_out(annotated);
7
+ assert.equal(output.code, annotated.representatives["nat"]);
8
+ assert.equal(input.code, annotated.representatives["nat"]);
9
+ console.log("OK");
10
+ });
@@ -0,0 +1,14 @@
1
+ import { t, in_out } from './index.mjs';
2
+ import assert from 'assert';
3
+
4
+ t(`$b = < {} true, {} false > ;
5
+ true = {{} true} $b;
6
+ false = {{} false} $b;
7
+ not = $b < .true false, .false true >;
8
+ not not
9
+ `, (annotated) => {
10
+ const {input,output} = in_out(annotated);
11
+ assert.equal(input.code, annotated.representatives["b"]);
12
+ assert.equal(output.code, annotated.representatives["b"]);
13
+ console.log("OK");
14
+ });
@@ -0,0 +1,21 @@
1
+ import { t, in_out } from './index.mjs';
2
+ import assert from 'assert';
3
+
4
+ t('{}', (annotated) => {
5
+ const {input,output} = in_out(annotated);
6
+ assert.equal(input.type, null);
7
+ assert.equal(output.code, annotated.representatives["{}"]);
8
+ console.log("OK");
9
+ });
10
+
11
+ t(`
12
+ $b = < {} true, {} false > ;
13
+ $pair = { b one, b two } ;
14
+
15
+ {() one, () two} $pair
16
+ `, (annotated) => {
17
+ const {input,output} = in_out(annotated);
18
+ assert.equal(input.code, annotated.representatives["b"]);
19
+ assert.equal(output.code, annotated.representatives["pair"]);
20
+ console.log("OK");
21
+ });
@@ -0,0 +1,14 @@
1
+ import { t, in_out } from './index.mjs';
2
+ import assert from 'assert';
3
+
4
+ t(`
5
+ $nat = < {} _, nat 0, nat 1>;
6
+ zero = {{{} _} 0} $nat;
7
+ rlz = <.0._ zero, .0 rlz, ()>;
8
+ rlz
9
+ `, (annotated) => {
10
+ const {input,output} = in_out(annotated);
11
+ assert.equal(output.code, annotated.representatives["nat"]);
12
+ assert.equal(input.code, annotated.representatives["nat"]);
13
+ console.log("OK");
14
+ });
@@ -0,0 +1,28 @@
1
+ import { t, in_out } from './index.mjs';
2
+ import assert from 'assert';
3
+
4
+ t('[]', (annotated) => {
5
+ const {input,output} = in_out(annotated);
6
+ assert.equal(input.type, null);
7
+ assert.equal(output.type, "vector");
8
+ console.log("OK");
9
+ });
10
+
11
+ t(`$int [ $int true, false ]`, (annotated) => {
12
+ const {input,output} = in_out(annotated);
13
+ assert.equal(input.code, "int");
14
+ assert.equal(output.type, "vector");
15
+ console.log("OK");
16
+ });
17
+
18
+ t(`$int [ $int true, false ] .0`, (annotated) => {
19
+ const {input,output} = in_out(annotated);
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(`[]`);
package/INTRO.md ADDED
@@ -0,0 +1,88 @@
1
+ ### Introduction to Kernel/Core
2
+
3
+ **Kernel/Core** is a minimal, gradually typed, first-order functional programming language designed for defining and transforming data using partial functions. It is built on the foundation of Algebraic Data Types (ADTs), specifically tagged unions and products.
4
+
5
+ #### Core Concepts
6
+
7
+ 1. **Statements**:
8
+ - The program consists of a possibly empty list of statements, each ending with a semicolon (`;`), followed by an expression.
9
+ - There are two types of statements:
10
+ - **Code Definitions**: Define data types and start with a dollar sign (`$`).
11
+ - **Relation Definitions**: Define partial functions (transformations) of data.
12
+
13
+ 2. **Codes**:
14
+ - Codes represent data types and can be either unions (`<...>`) or products (`{...}`).
15
+ - Example:
16
+ ```kernelcore
17
+ $ bool = <{} true, {} false>;
18
+ $ pair_of_bools = {bool x, bool y};
19
+ ```
20
+
21
+ 3. **Relations**:
22
+ - Relations are partial functions defined to transform data from one type to another.
23
+ - Example:
24
+ ```kernelcore
25
+ is_x_true = $pair_of_bools (.x .true);
26
+ ```
27
+
28
+ 4. **Composition of Partial Functions**:
29
+ - **Sequential (Functional) Composition**: Sequential application of partial functions.
30
+ ```kernelcore
31
+ (.x .true)
32
+ ```
33
+ - **Parallel (Product) Composition**: Combine multiple partial functions to construct a new product type.
34
+ ```kernelcore
35
+ {.x x_value, .y y_value}
36
+ ```
37
+ - **Concurrent (Union) Composition**: Try different functions in sequence, returning the first successful result.
38
+ ```kernelcore
39
+ <{.x .true false_bool}, {} true_bool>
40
+ ```
41
+
42
+ 5. **Constants**:
43
+ - Constants are defined as partial functions that ignore their input.
44
+ - Example:
45
+ ```kernelcore
46
+ true_bool = {{} true} $bool;
47
+ false_bool = {{} false} $bool;
48
+ ```
49
+
50
+ #### Example Program
51
+
52
+ ```kernelcore
53
+ // Define a boolean type as a union of true and false
54
+ $ bool = <{} true, {} false>;
55
+
56
+ // Define a pair of booleans as a product of two booleans
57
+ $ pair_of_bools = {bool x, bool y};
58
+
59
+ // Check if the `x` field is `true`
60
+ is_x_true = $pair_of_bools (.x .true);
61
+
62
+ // Extract both `x` and `y` fields into a new product
63
+ extract_both = $pair_of_bools {.x x_value, .y y_value} $pair_of_bools;
64
+
65
+ // Check if either `x` or `y` is `true`
66
+ is_any_true = $pair_of_bools <{.x .true false_bool}, {} true_bool> $bool;
67
+
68
+ // Define constants
69
+ true_bool = {{} true} $bool;
70
+ false_bool = {{} false} $bool;
71
+
72
+ // Create instances of `pair_of_bools`
73
+ pair1 = {true_bool x, true_bool y} $pair_of_bools;
74
+ pair2 = {true_bool x, false_bool y} $pair_of_bools;
75
+ pair3 = {false_bool x, false_bool y} $pair_of_bools;
76
+
77
+ // Example usage of the functions
78
+ result1 = pair1 is_x_true; // Should return true
79
+ result2 = pair2 is_x_true; // Should return true
80
+
81
+ both_values = pair1 extract_both; // Should return {x_value true, y_value true}
82
+
83
+ any_true1 = pair1 is_any_true; // Should return true
84
+ any_true2 = pair2 is_any_true; // Should return true
85
+ any_true3 = pair3 is_any_true; // Should return false
86
+ ```
87
+
88
+ This brief introduction covers the fundamental concepts of Kernel/Core, enabling you to start defining data types and writing partial functions to transform data.
package/README.md CHANGED
@@ -76,9 +76,10 @@ There are three ways of combining functions:
76
76
  ### Syntactic sugar
77
77
 
78
78
  - parenthesis can be omitted, except for the empty composition `()`,
79
- - dot (`.`) in "projection" acts as a separator so the space around it can be omitted.
79
+ - dot (`.`) in "projection" acts as a separator so the space around it
80
+ can be omitted.
80
81
 
81
- For example, `[(.toto .titi (.0 .1))]` can be written as `[.toto.titi.0.1]`.
82
+ For example, `(.toto .titi (.0 .1))` can be written as `.toto.titi.0.1`.
82
83
 
83
84
  Comments can be introduced by `//`, `--`, `%`, or `#` and extends to
84
85
  the end of line. Multiline `C`-like comments, `/* ... */`, are also
@@ -118,8 +119,9 @@ projection to the canonicat string representation of the value, e.g.:
118
119
  #### Vector product
119
120
 
120
121
  Vector product can be seen as an abbreviation for product whose field
121
- names are integers starting from zero. E.g., `{.toto 0, .titi 1, 123 2}`
122
- can be written as `[.toto, .titi, 123]`.
122
+ names are integers starting from zero.
123
+ E.g., `{.toto 0, .titi 1, 123 2}` can be written as
124
+ `[.toto, .titi, 123]`.
123
125
 
124
126
  [.toto, .titi, 12] :
125
127
  {"toto": 5, "titi": 10 } --> [5, 10, 12]
@@ -128,6 +130,9 @@ can be written as `[.toto, .titi, 123]`.
128
130
  ["A","B","C"] --> "B"
129
131
  ["a"] ... undefined
130
132
 
133
+ The vector notation is introduced to satisfy JSON syntax and, for example,
134
+ is not supported in _code derivation_ (explained below).
135
+
131
136
  ---
132
137
 
133
138
  ### Pragmatic extensions, aka "standard library"
@@ -172,8 +177,8 @@ can be written as `[.toto, .titi, 123]`.
172
177
  "[1,2.11,0.3e-32]" --> [1,2.11,3e-33]
173
178
 
174
179
 
175
- - other predefined parial functions are: `DIV`, `FDIV`, `CONS`, `SNOC`, `toDateMsec`,
176
- `toDateStr`, and `_log!`.
180
+ - other predefined parial functions are: `DIV`, `FDIV`, `CONS`,
181
+ `SNOC`, `toDateMsec`, `toDateStr`, and `_log!`.
177
182
 
178
183
  ---
179
184
 
@@ -183,7 +188,8 @@ can be written as `[.toto, .titi, 123]`.
183
188
  max = <SNOC [.0, .1 max] <GT.0, .1>, .0> ;
184
189
  factorial = < [(),0] GT .0 [dec factorial, ()] TIMES, 1 >;
185
190
 
186
- _Codes_ (prefixed by `$`) can be defined by taged union and product. E.g.:
191
+ ### Codes (schemas, i.e., _non-functional types_)
192
+ _Codes_ (prefixed by `$`) can be defined by tagged union and product. E.g.:
187
193
 
188
194
 
189
195
  $nat = <nat 1, {} 0>;
@@ -192,18 +198,67 @@ _Codes_ (prefixed by `$`) can be defined by taged union and product. E.g.:
192
198
  suc = {$nat 1};
193
199
  add = $pair <{.x.1 x, .y suc y} add, .y>;
194
200
 
201
+ Two codes are considered equal when they are isomorphic (preserving
202
+ union/product and field names). E.g., `$pair`, `${nat y, nat x}`, and
203
+ `${<nat 1, {} 0> x, nat y}` are all equal.
204
+
195
205
  #### Basic extension codes
196
206
 
197
- Since _basic extension_ introduces integers, booleans, and strings, there are three
198
- predefined types: `int`, `bool`, and `string`. A vector product code can also be defined
199
- by `[ codeExp ]`. All members of the vector are the same code. E.g.,
207
+ Since _basic extension_ introduces integers, booleans, and strings,
208
+ there are three predefined types: `int`, `bool`, and `string`. A
209
+ vector product code can also be defined by `[ codeExp ]`. All members
210
+ of the vector are the same code. E.g.,
200
211
 
201
212
  $intVector = [ int ];
202
213
  $boolVector = [ bool ];
203
214
  $tree = [ tree ];
204
215
 
205
- emptyList? = $intVector $[ string ]; -- as only an empty vector can be a vector
206
- -- of integers and a vector of strings
216
+ ### Code derivation and Patterns
217
+
218
+ Intuitively, a _pattern_ represents some set of contraints on
219
+ codes. For example, expression `.toto` is a projection from a value of
220
+ a product or a union with field `toto`. Therefore, expression `.toto`
221
+ introduces two patterns `p_i` and `p_o` (for input and output codes,
222
+ respectively); `p_o` imposes no constraint on code, however `p_i` is a
223
+ product or union code with field `toto` leading to a code fulfilling
224
+ `p_o`, i.e., something like `< ? toto, ... >` or `{ ? toto, ... }`.
225
+
226
+ .toto
227
+ p_i p_o
228
+
229
+ In a more complex expression each (occurrence of) subexpression will
230
+ introduce some new patterns.
231
+ For example, concider `<.toto, ()>`:
232
+
233
+ < .toto , () >
234
+ p1 p2 p3 p4 p5 p6
235
+
236
+ where `p1` is the pattern for the input code of the whole expression,
237
+ and `p6` is the pattern for the output. We can deduce that patterns
238
+ (`p1`, `p2`, `p4`) defines the same code, as well as (`p6`, `p5`, `p3`),
239
+ because union combines partial functions with the same input and output codes.
240
+ Identity, `()`, implies that (`p4`, `p5`) define the
241
+ same code. That means that in our expression, we deal with only one
242
+ code, `c`, product or union, with field `toto` of type `c`, i.e.,
243
+
244
+ $c = < c toto, ... >;
245
+
246
+ or
247
+
248
+ $c = { c toto, ... };
249
+
250
+ Since the product code pattern (i.e., latter case) doesn't admmit any
251
+ (finite) value, we conclude that the code `c` is a union (i.e.,
252
+ former case).
253
+
254
+ For a given `kScript`, code derivation (as any static analysis) can
255
+ fail, indicating that the script is invalid. In some other cases the
256
+ code derivation can succeed even to the point of reducig every pattern
257
+ to a single code making the program fully annotated by codes.
258
+
259
+ For now, `code derivation` is supported by the core language, i.e., `composition`,
260
+ `projection` and `union` with product and tagged union types.
261
+
207
262
  ---
208
263
 
209
264
  ### List comprehension on vectors (experimental!)
@@ -259,8 +314,7 @@ times value `x` appears in the list. (see `Examples/list-comprehension.k` for a
259
314
  ."field name"
260
315
  .4
261
316
 
262
- The function is defined only if its argument is a structure with
263
- the field (or a vector with the index).
317
+ The function is defined if its argument "has" the field.
264
318
 
265
319
  2. _constants_, literals for Strings, Booleans, and
266
320
  Integers. Examples:
package/TODO.md ADDED
@@ -0,0 +1,54 @@
1
+ # TODO list
2
+
3
+ - [ ] Incremental compilation
4
+ - [ ] After `annotation` is done, find fully closed patterns, turn them into codes, then rerun
5
+ the code minimization step
6
+ - [ ] Named relations can be polymorphic:
7
+ -- can we introduce polymorphic patterns? E.g.,: `{ .x if, .y then} .then`.
8
+ Here, the input pattern could be "open" product with two fields `.x` and `.y`, end the ouput pattern could be the pattern of field `.y`.
9
+ -- should we introduce a scope (e.g., syntactic or dynamic?) for all calls to the relation and
10
+ run annotations for all scopes separately?
11
+ - [ ] Implement support for different relations under a same name as long as they have
12
+ "very" different input or output patterns.
13
+ - [ ] In type graphs, we should detect cycles over only product types and reject such programs, e.g.,:
14
+
15
+ ```k
16
+ $boo = {{} _, boo b};
17
+ ```
18
+
19
+ ---
20
+
21
+ ## Type system
22
+
23
+ Example:
24
+
25
+ ```Examples/pats.k
26
+ xy = .x y;
27
+ y = .y;
28
+ $A = < {} a, {} other >;
29
+ $B = < {} b, {} other >;
30
+ $ya = < {} a, $A y >;
31
+ $yb = < {} b, $B y >;
32
+ $input = {{ya x, {} y} one, {yb x, {} y} two};
33
+ $input {.one xy one, .two xy two}
34
+ ```
35
+
36
+ We would like to correctly type the above program as `$input -> { A one, B two }`.
37
+
38
+ filters for typing `__main__`:
39
+
40
+ ```?
41
+ __main__
42
+ 0 / \ 1
43
+ / \
44
+ $input {.one xy one, .two xy two}
45
+ 2 3 4 / \ 5
46
+ / \
47
+ (.one xy) (.two xy)
48
+ / \ / \
49
+ 6 / \ 7 8 / \ 9
50
+ / \ / \
51
+ .one xy .two xy
52
+ 10 11 12 13 14 15 16 17
53
+
54
+ ```