@fraczak/k 4.0.3 → 5.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 +28 -21
- package/README.md +158 -154
- package/TODO.md +18 -0
- package/TYPING.md +2 -2
- package/export.mjs +177 -0
- package/index.mjs +3 -15
- package/k-repl.cast +1913 -0
- package/k.cast +618 -0
- package/package.json +1 -1
- package/patterns.mjs +22 -8
- package/pretty.mjs +26 -41
- package/repl.mjs +47 -28
- package/run.mjs +5 -1
- package/TYPES.md +0 -32
- package/demo.cast +0 -1772
- package/demo.gif +0 -0
- package/demo2.cast +0 -1705
- package/demo_optimized.gif +0 -0
- package/sc.py +0 -25
package/BIG_PICTURE.md
CHANGED
|
@@ -25,8 +25,10 @@ Types are defined by two constructs:
|
|
|
25
25
|
|
|
26
26
|
Given a finite (possibly empty) set of types `t1, t2, ..., tn` and a set of pairwise different tags (labels) `l1, l2, ..., ln`,
|
|
27
27
|
|
|
28
|
-
- by `{ t1 l1, t2 l2, ..., tn ln }`, we define a _product type_ with exactly `n`
|
|
29
|
-
|
|
28
|
+
- by `{ t1 l1, t2 l2, ..., tn ln }`, we define a _product type_ with exactly `n`
|
|
29
|
+
_projection_ functions: `.l1`, `.l2`, `...`, `.ln`.
|
|
30
|
+
Each projection function is mapping a value of type `{t1 l1, t2 l2, ..., tn ln}`
|
|
31
|
+
into a value of type `t1`, `t2`, `...`, `tn`, respectively.
|
|
30
32
|
- by `< t1 l1, t2 l2, ..., tn ln >`, we define a _union type_ with exactly `n` projection functions `.l1`, `.l2`, `...`, `.ln`,
|
|
31
33
|
mapping a value of type `<t1 l1, t2 l2, ..., tn ln>` into a value of type `t1`, `t2`, `...`, `tn`, respectively.
|
|
32
34
|
|
|
@@ -38,8 +40,8 @@ Some properties of these types:
|
|
|
38
40
|
|
|
39
41
|
1. Singleton product and singleton union types, `{ t label }` and `< t label >`, are equivalent as they have
|
|
40
42
|
the same set of values (and the same projection function `.label`). That's why, we not allow singleton product nor
|
|
41
|
-
singleton union types in the syntax of the language. The other benefit is that we will be able to use the same
|
|
42
|
-
for values of both product and union types, interpretting every singleton product-like value, e.g., `{ a_value label }`,
|
|
43
|
+
singleton union types in the syntax of the language. The other benefit is that we will be able to use the same syntax
|
|
44
|
+
for writing out values of both product and union types, interpretting every singleton product-like value, e.g., `{ a_value label }`,
|
|
43
45
|
as a union type value (a variant).
|
|
44
46
|
2. The empty product type `{}` has a single value, called the _unit_ and also denoted by `{}`, which has no fields.
|
|
45
47
|
3. The empty union type `<>` has no values.
|
|
@@ -50,7 +52,7 @@ A _partial function_ is a function that is not defined for every value of its do
|
|
|
50
52
|
|
|
51
53
|
There are three ways of combining partial functions:
|
|
52
54
|
|
|
53
|
-
1. __Composition__: we write a composition of `f` and `g` as `(f g)`, meaning that if `f` is defined on
|
|
55
|
+
1. __Composition__: we write a composition of `f` and `g` as `(f g)`, meaning that if `f` is defined on value `x` producing `y`,
|
|
54
56
|
and `g` is defined on value `y` producing `z`, then `(f g)` is defined on value `x` producing `z`.
|
|
55
57
|
2. __Union__: we write `< f1, f2 >` for a union of two functions `f1` and `f2`, meaning that
|
|
56
58
|
if `f1` is defined on value `x` producing `y`, then `< f1, f2 >`
|
|
@@ -59,7 +61,7 @@ There are three ways of combining partial functions:
|
|
|
59
61
|
are both defined on value `x` producing `y1` and `y2`, respectively, then `{f1 lab1, f2 lab2 }`
|
|
60
62
|
is defined on value `x` producing `{y1 lab1, y2 lab2}`. Otherwise, `{f1 lab1, f2 lab2 }` is not defined for `x`.
|
|
61
63
|
|
|
62
|
-
Actually,
|
|
64
|
+
Actually, composition, union, and product combine any number of partial functions, not only two. For example,
|
|
63
65
|
empty composition, `()`, defines the identity function.
|
|
64
66
|
|
|
65
67
|
### Program
|
|
@@ -78,16 +80,21 @@ type_label_list ::= /* empty */ | ( type_expression label_name ',' ) + type_expr
|
|
|
78
80
|
type_expression ::= type_name | type
|
|
79
81
|
|
|
80
82
|
function_definition ::= function_name '=' expression ';'
|
|
81
|
-
expression ::= projection | typing | composition | union | product | function_name
|
|
83
|
+
expression ::= projection | typing | filter | composition | union | product | function_name
|
|
82
84
|
projection ::= '.' label_name
|
|
83
|
-
typing ::= '$'
|
|
85
|
+
typing ::= '$' type_expression
|
|
86
|
+
filter ::= '?' filter_expression
|
|
87
|
+
filter_expression ::= $ type_expression | filter_name
|
|
88
|
+
| '{' filter_label_list '}' | '<' filter_label_list '>' | '(' filter_label_list ')'
|
|
89
|
+
| filter_expression '=' filter_name
|
|
90
|
+
filter_label_list ::= /* empty */ | ( filter_expression label_name ',' ) * filter_expression label
|
|
84
91
|
composition ::= '(' expression * ')'
|
|
85
92
|
union ::= '<' (expression ',') + expression '>'
|
|
86
93
|
product ::= '{' expression_label_list '}'
|
|
87
94
|
expression_label_list ::= /* empty */ | ( expression label_name ',' ) * expression label
|
|
88
95
|
```
|
|
89
96
|
|
|
90
|
-
We assume that the `type_name`, `function_name`, and `label_name` are identifiers (strings) such that:
|
|
97
|
+
We assume that in a `kernel-core` program the `type_name`, `function_name`, and `label_name` are identifiers (strings) such that:
|
|
91
98
|
|
|
92
99
|
1. All defined type names are distinct.
|
|
93
100
|
2. All defined function names are distinct.
|
|
@@ -97,6 +104,7 @@ The `typing` expression acts as a type annotation and can be seen as a 'filter',
|
|
|
97
104
|
function defined only for the values of the corresponding type.
|
|
98
105
|
|
|
99
106
|
That's it.
|
|
107
|
+
|
|
100
108
|
No `builtin` types, no `if` statement, no `loop`, no `throw`, no _closure_, no _annotations_, and no macros.
|
|
101
109
|
Just types and partial functions.
|
|
102
110
|
|
|
@@ -104,22 +112,22 @@ Just types and partial functions.
|
|
|
104
112
|
|
|
105
113
|
All type names are replaced by the hash of their canonical representation.
|
|
106
114
|
|
|
107
|
-
We
|
|
108
|
-
Obviously,
|
|
115
|
+
We replace the function name by the hash of the normalized definition of the function as provided by the program defining the function.
|
|
116
|
+
Obviously, a function may have many different definitions so the hash-based names are not canonical. By using hash-based function names we avoid the problem of name clashes when bringing together many `kernel-core` programs.
|
|
109
117
|
|
|
110
|
-
This approach solves the problem of modules
|
|
118
|
+
This approach solves the problem of modules, imports, etc., and opens the door to a universal
|
|
111
119
|
registry of types (schemas) and functions.
|
|
112
120
|
|
|
113
121
|
## Typing and Polymorphism (codes and filters/patterns)
|
|
114
122
|
|
|
115
|
-
Abstract Syntax Tree of a program
|
|
123
|
+
Abstract Syntax Tree of a program consists of a dictionary of _type definitions_,
|
|
116
124
|
a dictionary of _function definitions_, and the final _main expression_.
|
|
117
125
|
|
|
118
126
|
In principle, the initial form of the Abstract Syntax Tree, _raw_ AST, is enough to evaluate
|
|
119
127
|
the program on an input.
|
|
120
128
|
|
|
121
129
|
Our objective however is to compute canonicals representations for types and normalized
|
|
122
|
-
representations for functions, so they could be
|
|
130
|
+
representations for functions, so they could be reused.
|
|
123
131
|
|
|
124
132
|
The normalization steps are:
|
|
125
133
|
|
|
@@ -127,7 +135,7 @@ The normalization steps are:
|
|
|
127
135
|
as well as type expressions used in _function definitions_ and the _main expression_.
|
|
128
136
|
2. Annotate the expressions with types or type patterns; every node of the AST is annotated with a pair of type patterns.
|
|
129
137
|
3. Turn the _singleton_ type patterns into types and add them to the _type graph_. Go to (2) unless no change.
|
|
130
|
-
|
|
138
|
+
|
|
131
139
|
|
|
132
140
|
### Example
|
|
133
141
|
|
|
@@ -169,7 +177,7 @@ and a type `byte` as a product, for simplicity, of four `bit`s.
|
|
|
169
177
|
Functions `bit0`, `bit1`, and `zero` are "constant polymorphic functions", meaning:
|
|
170
178
|
|
|
171
179
|
- constant: if defined, they always return exactly the same value;
|
|
172
|
-
- polymorphic: they are defined for more than one pair of input and output
|
|
180
|
+
- polymorphic: they are defined for more than one pair of input and output types: functions
|
|
173
181
|
`bit0` and `bit1` are of type `?X -> $bit`, and `zero` is of type `?X -> $byte`, where `?X`
|
|
174
182
|
denotes an unconstrained type pattern, also denoted as `?(...)`.
|
|
175
183
|
|
|
@@ -186,15 +194,15 @@ with following constraints:
|
|
|
186
194
|
> `?( V i, ...)`;
|
|
187
195
|
- `V` is unconstrained, denoted by `(...)`;
|
|
188
196
|
|
|
189
|
-
We
|
|
197
|
+
We can write it as: `?($byte byte, ((...) i, ...) overflown, ...)`.
|
|
190
198
|
|
|
191
199
|
The target type `${ byte byte, bit overflown }` was derived from pattern `?{ $byte byte, $bit overflown }`.
|
|
192
|
-
Such a
|
|
200
|
+
Such a pattern is called _singleton pattern_, as only one type fits the pattern.
|
|
193
201
|
|
|
194
202
|
## Universal Schema Registry
|
|
195
203
|
|
|
196
204
|
Since the normalization process for types is fast and deterministic, we can build a universal
|
|
197
|
-
schema registry that will store all invented types.
|
|
205
|
+
schema registry that will store all invented types.
|
|
198
206
|
The registry will be a key-value store, where the key is the hash of the normalized type,
|
|
199
207
|
and the value is the normalized type itself.
|
|
200
208
|
|
|
@@ -203,8 +211,7 @@ definition and stored in the similar key-value store.
|
|
|
203
211
|
|
|
204
212
|
Non-polymorphic functions can be easily indexed by the hashes of their input and output types
|
|
205
213
|
so that we can quickly find the function we need.
|
|
206
|
-
|
|
207
|
-
whose input and output type patterns fit given types.
|
|
214
|
+
Indexing polymorphic functions seems complicated (TODO).
|
|
208
215
|
|
|
209
216
|
## Serialization and Compilation
|
|
210
217
|
|
package/README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# k-language
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
```sh
|
|
4
|
+
npm i '@fraczak/k'
|
|
5
|
+
```
|
|
4
6
|
|
|
5
7
|
From javascript:
|
|
6
8
|
|
|
7
|
-
```
|
|
9
|
+
```javascript
|
|
8
10
|
import k from "@fraczak/k"
|
|
9
11
|
|
|
10
12
|
const fn = k.compile(` -- complete "pure" k-program
|
|
@@ -16,39 +18,11 @@ const three = {i:{i:{i:{o:{}}}}};
|
|
|
16
18
|
const six = fn(three);
|
|
17
19
|
console.log(JSON.stringify( six ));
|
|
18
20
|
// {"i":{"i":{"i":{"i":{"i":{"i":{"o":{}}}}}}}}
|
|
19
|
-
|
|
20
21
|
```
|
|
21
22
|
|
|
22
23
|
Working with REPL:
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
$ k-repl
|
|
26
|
-
Very! experimental repl shell for 'k-language'...
|
|
27
|
-
--c print aliased codes
|
|
28
|
-
--C code print 'code' definition
|
|
29
|
-
--r print relations
|
|
30
|
-
--R rel print 'rel' definition with type patterns
|
|
31
|
-
--p (--pp) pretty-print last value
|
|
32
|
-
--s (--g) reg store (get) the current value in (from) register 'reg'
|
|
33
|
-
--regs print register names
|
|
34
|
-
--l file.k load 'file.k'
|
|
35
|
-
> -- DEMO: comments start with '--', like this line \
|
|
36
|
-
-- Code (type) definitions: ` $ code-name = code-expression ;` \
|
|
37
|
-
$ unit = { } ; -- empty product code \
|
|
38
|
-
$ bits = <unit _, bits 0, bits 1>; -- union, 3 variants tagged: _, 0, 1 \
|
|
39
|
-
-- Now, we will define relations: ` name = expression ; ` \
|
|
40
|
-
empty = {{} _} ; -- alternative JSON-like syntax {_: {}} allowed \
|
|
41
|
-
_001 = {0: {0: {1: empty}}}; -- in JSON-like syntax \
|
|
42
|
-
reverse_ = < -- priority merge \
|
|
43
|
-
{.in.0 in, {.out 0} out} reverse_, \
|
|
44
|
-
{.in.1 in, {.out 1} out} reverse_, \
|
|
45
|
-
.out >; \
|
|
46
|
-
reverse = {() in, empty out} reverse_ ; \
|
|
47
|
-
_001 reverse -- run the expression (composition of 2 relations)
|
|
48
|
-
--> {"1":{"0":{"0":{"_":{}}}}}
|
|
49
|
-
> toStr = < .0 ["0",toStr] CONCAT, .1 ["1",toStr] CONCAT, "" >; toStr
|
|
50
|
-
--> "100"
|
|
51
|
-
```
|
|
25
|
+
[](https://asciinema.org/a/UZuFpX4a5CQ47JTQngv253EVv)
|
|
52
26
|
|
|
53
27
|
---
|
|
54
28
|
|
|
@@ -60,9 +34,11 @@ An example of a _partial function_ is the _projection_, e.g., "`.toto`",
|
|
|
60
34
|
which maps an object to its property named `toto`, or it is not defined if
|
|
61
35
|
the property doesn't exist. E.g.,
|
|
62
36
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
37
|
+
```text
|
|
38
|
+
1 .toto :
|
|
39
|
+
2 {"toto": 5, "titi": 10} --> 5
|
|
40
|
+
3 {"titi": 10} ... undefined // it is not a value!
|
|
41
|
+
```
|
|
66
42
|
|
|
67
43
|
> Note: The above 3 lines should be read as follows. A `k`-expression
|
|
68
44
|
> is printed in the first line (before "`:`"). The following lines
|
|
@@ -81,25 +57,30 @@ There are three ways of combining functions:
|
|
|
81
57
|
1. **composition**: `(f1 f2 ...)`, e.g. `(.toto .titi)` extracts
|
|
82
58
|
nested field.
|
|
83
59
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
60
|
+
```text
|
|
61
|
+
(.toto .titi) :
|
|
62
|
+
{"toto": {"titi": 10}} --> 10
|
|
63
|
+
{"toto": {"other": 8}} ... undefined
|
|
64
|
+
{"other": {}} ... undefined
|
|
65
|
+
```
|
|
88
66
|
|
|
89
67
|
2. **merge**: `< f1, f2,... >`, e.g., `<.toto, .titi>` extracts field
|
|
90
68
|
`toto` if present; otherwise extracts `titi`.
|
|
91
69
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
70
|
+
```text
|
|
71
|
+
< .x.y, .z.y > :
|
|
72
|
+
{"x":{"y": 5}, "z": {"y":10}} --> 5
|
|
73
|
+
{"x":{"o":{}}, "z": {"y":10}} --> 10
|
|
74
|
+
{"x":{"o":{}}, "z": {"o":{}}} ... undefined
|
|
75
|
+
```
|
|
96
76
|
|
|
97
77
|
3. **product**: `{ f1 label1, f2 label2, ...}`, e.g., `{.toto TOTO,
|
|
98
|
-
.titi TITI}` extracts two fields and builds a record out of them.
|
|
78
|
+
.titi TITI}` extracts two fields and builds a record out of them.
|
|
99
79
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
80
|
+
```text
|
|
81
|
+
{.toto TOTO, .titi TITI} :
|
|
82
|
+
{"toto": 5, "titi": 10, "x": 3} --> {"TOTO": 5, "TITI": 10}
|
|
83
|
+
```
|
|
103
84
|
|
|
104
85
|
---
|
|
105
86
|
|
|
@@ -132,46 +113,54 @@ supported.
|
|
|
132
113
|
A constant defines a function which ignores its argument and produces
|
|
133
114
|
the constant value. E.g.:
|
|
134
115
|
|
|
135
|
-
|
|
136
|
-
|
|
116
|
+
```text
|
|
117
|
+
{123 int, "kScript" str, true bool, null null} :
|
|
118
|
+
"any" --> {"int":123,"str":"kScript","bool":true,"null":null}
|
|
119
|
+
```
|
|
137
120
|
|
|
138
121
|
Those values, i.e., _strings_, _integers_, _booleans_, and _null_, admit the
|
|
139
|
-
projection to the
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
122
|
+
projection, via (`.`), to the canonical string representation of the value, e.g.:
|
|
123
|
+
|
|
124
|
+
```text
|
|
125
|
+
."a string" :
|
|
126
|
+
"a string" --> {}
|
|
127
|
+
"other" ... undefined
|
|
128
|
+
11 ... undefined
|
|
129
|
+
null ... undefined
|
|
130
|
+
.2 :
|
|
131
|
+
2 --> {}
|
|
132
|
+
"2" --> {}
|
|
133
|
+
4 ... undefined
|
|
134
|
+
true ... undefined
|
|
135
|
+
|
|
136
|
+
.true :
|
|
137
|
+
true --> {}
|
|
138
|
+
"true" --> {}
|
|
139
|
+
4 ... undefined
|
|
140
|
+
"toto" ... undefined
|
|
141
|
+
|
|
142
|
+
.null :
|
|
143
|
+
null --> {}
|
|
144
|
+
"null" --> {}
|
|
145
|
+
4 ... undefined
|
|
146
|
+
false ... undefined
|
|
147
|
+
```
|
|
158
148
|
|
|
159
149
|
#### Vector product
|
|
160
150
|
|
|
161
|
-
Vector product can be seen as an abbreviation for product whose
|
|
162
|
-
names are integers starting from zero.
|
|
151
|
+
Vector product can be seen as an abbreviation for product whose all fields
|
|
152
|
+
have the same type, and the filed names are integers starting from zero.
|
|
163
153
|
E.g., `{.toto 0, .titi 1, 123 2}` can be written as
|
|
164
154
|
`[.toto, .titi, 123]`.
|
|
165
155
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
.1 :
|
|
170
|
-
["A","B","C"] --> "B"
|
|
171
|
-
["a"] ... undefined
|
|
156
|
+
```text
|
|
157
|
+
[.toto, .titi, 12] :
|
|
158
|
+
{"toto": 5, "titi": 10 } --> [5, 10, 12]
|
|
172
159
|
|
|
173
|
-
|
|
174
|
-
|
|
160
|
+
. 2 :
|
|
161
|
+
["A","B","C"] --> "C"
|
|
162
|
+
["a"] ... undefined
|
|
163
|
+
```
|
|
175
164
|
|
|
176
165
|
---
|
|
177
166
|
|
|
@@ -204,7 +193,7 @@ is not supported in _code derivation_ (explained below).
|
|
|
204
193
|
|
|
205
194
|
CONCAT:
|
|
206
195
|
["a","bc","d"] --> "abcd"
|
|
207
|
-
[
|
|
196
|
+
[] --> ""
|
|
208
197
|
|
|
209
198
|
- `toJSON` and `fromJSON` -- conversion to and from JSON strings
|
|
210
199
|
|
|
@@ -213,8 +202,6 @@ is not supported in _code derivation_ (explained below).
|
|
|
213
202
|
|
|
214
203
|
fromJSON:
|
|
215
204
|
"{\"a\":12}" --> {"a":12}
|
|
216
|
-
"2.12" --> 2.12
|
|
217
|
-
"[1,2.11,0.3e-32]" --> [1,2.11,3e-33]
|
|
218
205
|
|
|
219
206
|
- other predefined parial functions are: `DIV`, `FDIV`, `CONS`,
|
|
220
207
|
`SNOC`, `toVEC`, `toDateMsec`, `toDateStr`, and `_log!`.
|
|
@@ -223,24 +210,47 @@ is not supported in _code derivation_ (explained below).
|
|
|
223
210
|
|
|
224
211
|
### Function and code (i.e., _type_) definitions
|
|
225
212
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
213
|
+
```k-repl
|
|
214
|
+
dec = [(),-1] PLUS;
|
|
215
|
+
max = <SNOC [.car, .cdr max] <GT.0, .1>, .0> ;
|
|
216
|
+
factorial = < [(),0] GT .0 [dec factorial, ()] TIMES, 1 >;
|
|
217
|
+
6 factorial
|
|
218
|
+
--> 720
|
|
219
|
+
```
|
|
229
220
|
|
|
230
221
|
### Codes (schemas, i.e., _types_)
|
|
231
222
|
|
|
232
|
-
_Codes_
|
|
223
|
+
_Codes_ can be defined by tagged union and product. E.g.:
|
|
233
224
|
|
|
225
|
+
```k-repl
|
|
226
|
+
$ nat = < nat 1, {} 0 >;
|
|
227
|
+
$ pair = { nat x, nat y };
|
|
234
228
|
|
|
235
|
-
|
|
236
|
-
|
|
229
|
+
suc = { $ nat 1 };
|
|
230
|
+
add = $ pair <{.x.1 x, .y suc y} add, .y>;
|
|
231
|
+
```
|
|
237
232
|
|
|
238
|
-
|
|
239
|
-
|
|
233
|
+
Code definition statement starts with `$`.
|
|
234
|
+
Also, any code expression occurrig within a `k`-expression is prefixed by `$`.
|
|
240
235
|
|
|
241
236
|
Two codes are considered equal when they are isomorphic (preserving
|
|
242
237
|
union/product and field names). E.g., `$pair`, `${nat y, nat x}`, and
|
|
243
|
-
`${<nat 1, {} 0> x, nat y}` are all
|
|
238
|
+
`${<nat 1, {} 0> x, nat y}` are all equivalent and corresponds its cannonical form
|
|
239
|
+
`$C0={C1"x",C1"y"};$C1=<C2"0",C1"1">;$C2={};`.
|
|
240
|
+
|
|
241
|
+
Try in `k-repl`:
|
|
242
|
+
|
|
243
|
+
```k-repl
|
|
244
|
+
> $ nat = < nat 1, {} 0 >; \
|
|
245
|
+
$ pair = { nat x, nat y };
|
|
246
|
+
--> {}
|
|
247
|
+
> --C pair
|
|
248
|
+
$ IxLVRLECv = {BADJOX x, BADJOX y}; -- $C0={C1"x",C1"y"};$C1=<C2"0",C1"1">;$C2={};
|
|
249
|
+
$ myCode = {<nat 1, {} 0> x, nat y};
|
|
250
|
+
--> {}
|
|
251
|
+
> --C myCode
|
|
252
|
+
$ IxLVRLECv = {BADJOX x, BADJOX y}; -- $C0={C1"x",C1"y"};$C1=<C2"0",C1"1">;$C2={};
|
|
253
|
+
```
|
|
244
254
|
|
|
245
255
|
#### Basic extension codes
|
|
246
256
|
|
|
@@ -249,26 +259,33 @@ there are three predefined types: `int`, `bool`, and `string`. A
|
|
|
249
259
|
vector product code can also be defined by `[ codeExp ]`. All members
|
|
250
260
|
of the vector are the same code. E.g.,
|
|
251
261
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
262
|
+
```k-repl
|
|
263
|
+
$ intVector = [ int ];
|
|
264
|
+
$ boolVector = [ bool ];
|
|
265
|
+
$ tree = [ tree ];
|
|
266
|
+
```
|
|
255
267
|
|
|
256
268
|
### Code derivation and Patterns
|
|
257
269
|
|
|
258
270
|
Intuitively, a _pattern_ represents some set of contraints on
|
|
259
271
|
codes. For example, expression `.toto` is a projection from a value of
|
|
260
|
-
a product or a union with field `toto`. Therefore, expression `.toto`
|
|
272
|
+
a product or a union code with field `toto`. Therefore, expression `.toto`
|
|
261
273
|
introduces two patterns `p_i` and `p_o` (for input and output codes,
|
|
262
274
|
respectively); `p_o` imposes no constraint on code, however `p_i` is a
|
|
263
275
|
product or union code with field `toto` leading to a code fulfilling
|
|
264
|
-
`p_o`,
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
276
|
+
`p_o`, which will be denoted by:
|
|
277
|
+
|
|
278
|
+
```k-repl
|
|
279
|
+
> toto = .toto;
|
|
280
|
+
--> {}
|
|
281
|
+
> --R toto
|
|
282
|
+
toto : ?(X0 toto, ...) --> ?X0
|
|
283
|
+
toto = .toto;
|
|
284
|
+
```
|
|
268
285
|
|
|
269
286
|
In a more complex expression each (occurrence of) subexpression will
|
|
270
287
|
introduce some new patterns.
|
|
271
|
-
For example, concider
|
|
288
|
+
For example, concider ` rel = <.toto, ()>; `.
|
|
272
289
|
|
|
273
290
|
< .toto , () >
|
|
274
291
|
p1 p2 p3 p4 p5 p6
|
|
@@ -278,28 +295,27 @@ and `p6` is the pattern for the output. We can deduce that patterns
|
|
|
278
295
|
(`p1`, `p2`, `p4`) defines the same code, as well as (`p6`, `p5`, `p3`),
|
|
279
296
|
because union combines partial functions with the same input and output codes.
|
|
280
297
|
Identity, `()`, implies that (`p4`, `p5`) define the
|
|
281
|
-
same code.
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
Since the product code pattern (i.e., latter case) doesn't admmit any
|
|
291
|
-
(finite) value, we conclude that the code `c` is a union (i.e.,
|
|
292
|
-
former case).
|
|
298
|
+
same code. In `k-repl`:
|
|
299
|
+
|
|
300
|
+
```k-repl
|
|
301
|
+
> rel = < .toto, () >;
|
|
302
|
+
--> {}
|
|
303
|
+
> --R rel
|
|
304
|
+
rel : ?(X0 toto, ...)=X0 --> ?X0
|
|
305
|
+
rel = <.toto, ()>;
|
|
306
|
+
```
|
|
293
307
|
|
|
294
308
|
For a given `kScript`, code derivation (as any static analysis) can
|
|
295
309
|
fail, indicating that the script is invalid. In some other cases the
|
|
296
310
|
code derivation can succeed even to the point of reducig every pattern
|
|
297
311
|
to a single code making the program fully annotated by codes.
|
|
298
312
|
|
|
299
|
-
The language `k` supports _type patterns_, which is used for
|
|
313
|
+
The language `k` supports _type patterns_, which is used for code
|
|
314
|
+
derivation, however the patterns are not concidered in the
|
|
315
|
+
evaluation of the program.
|
|
300
316
|
|
|
301
|
-
```k
|
|
302
|
-
|
|
317
|
+
```k-repl
|
|
318
|
+
treePattern = ?<(...) leaf, {T left, T right} tree> = T;
|
|
303
319
|
```
|
|
304
320
|
|
|
305
321
|
---
|
|
@@ -307,13 +323,13 @@ The language `k` supports _type patterns_, which is used for type inference, how
|
|
|
307
323
|
### List comprehension
|
|
308
324
|
|
|
309
325
|
A vector can be "open" by PIPE (`|`) operator so the following partial function is applied to
|
|
310
|
-
each element of the vector
|
|
326
|
+
each element of the vector, yielding another open value. An open value can be "closed",
|
|
311
327
|
i.e., turn into a regular vector using `CARET` (`^`) operator. E.g.:
|
|
312
328
|
|
|
313
329
|
```k
|
|
314
330
|
| .x ^ :
|
|
315
|
-
[{x:12}, {x:8
|
|
316
|
-
[
|
|
331
|
+
[{x:12}, {x:8}, {y:98}] --> [12,8]
|
|
332
|
+
["a","x","b","x"] --> [{},{}]
|
|
317
333
|
```
|
|
318
334
|
|
|
319
335
|
The PIPE operator can be used for defining the Cartesian product:
|
|
@@ -354,8 +370,8 @@ times value `x` appears in the list. (see `Examples/list-comprehension.k` for a
|
|
|
354
370
|
1. projection:
|
|
355
371
|
|
|
356
372
|
.x
|
|
357
|
-
."field name"
|
|
358
|
-
.4
|
|
373
|
+
. "field name"
|
|
374
|
+
(. 4)
|
|
359
375
|
|
|
360
376
|
The function is defined if its argument "has" the field.
|
|
361
377
|
|
|
@@ -398,11 +414,11 @@ times value `x` appears in the list. (see `Examples/list-comprehension.k` for a
|
|
|
398
414
|
Another example could be finding the biggest (max) value in a vector:
|
|
399
415
|
|
|
400
416
|
max = <
|
|
401
|
-
SNOC #
|
|
402
|
-
[.car, .cdr max] #
|
|
403
|
-
<GT .0, .1> #
|
|
417
|
+
SNOC # [x0, x1, x2, ...] --> {x0 car, [x1, x2, ...] cdr}
|
|
418
|
+
[.car, .cdr max] # {car:x0, cdr:[x1, x2, ...]} --> [x0, max(x1,x2,...)], recursive call
|
|
419
|
+
<GT .0, .1> # if x0 > max(x1,x2,...) then x0 else max(x1,x2,...)
|
|
404
420
|
, # when SNOC is not defined, i.e., if the input vector has one element:
|
|
405
|
-
.0 #
|
|
421
|
+
.0 # [x0] --> x0
|
|
406
422
|
>;
|
|
407
423
|
max
|
|
408
424
|
|
|
@@ -488,16 +504,16 @@ For example:
|
|
|
488
504
|
|
|
489
505
|
> k -k test.k
|
|
490
506
|
|
|
491
|
-
If we want to read `json` objects from a file, e.g., `my-objects.
|
|
507
|
+
If we want to read `json` objects from a file, e.g., `my-objects.jsonl`, we do
|
|
492
508
|
|
|
493
|
-
> k -k test.k my-objects.
|
|
509
|
+
> k -k test.k my-objects.jsonl
|
|
494
510
|
{"x&y":"x=432 & y=123"}
|
|
495
511
|
{"x&y":"only x=987"}
|
|
496
512
|
{"x&y":"no x nor y"}
|
|
497
513
|
|
|
498
514
|
where:
|
|
499
515
|
|
|
500
|
-
> cat my-objects.
|
|
516
|
+
> cat my-objects.jsonl
|
|
501
517
|
####################################################
|
|
502
518
|
# empty lines and lines starting with # are ignored
|
|
503
519
|
{"y": 123, "x": 432,"others": "..."}
|
|
@@ -509,40 +525,28 @@ For example:
|
|
|
509
525
|
|
|
510
526
|
### Short comparaison with `jq` tutorial examples: <https://stedolan.github.io/jq/tutorial/>
|
|
511
527
|
|
|
512
|
-
|
|
513
|
-
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | jq '.'
|
|
514
|
-
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | k '()' -1
|
|
515
|
-
2.
|
|
516
|
-
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | jq '.[0]'
|
|
517
|
-
curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | k '.0' -1
|
|
518
|
-
3.
|
|
519
|
-
jq '.[0] | {message: .commit.message, name: .commit.committer.name}'
|
|
520
|
-
k '.0 {.commit.message message, .commit.committer.name name}' -1
|
|
521
|
-
4. note: `k`-expression defines a partial function yielding a single json object, i.e., as far as `k` is concerned,
|
|
522
|
-
examples 4 and 5 of the `jq` tutorial are equivalent.
|
|
523
|
-
5.
|
|
524
|
-
jq '[.[] | {message: .commit.message, name: .commit.committer.name}]'
|
|
525
|
-
k '| .commit {.message message, .committer.name name} ^' -1
|
|
526
|
-
6.
|
|
527
|
-
jq '[.[] | {message: .commit.message, name: .commit.committer.name, parents: [.parents[].html_url]}]'
|
|
528
|
-
k '| {.commit.message message, .commit.committer.name name, .parents | .html_url ^ parents} ^' -1
|
|
528
|
+
[](https://asciinema.org/a/ItH7nkc5CwFOopH8Fsr23oCWj)
|
|
529
529
|
|
|
530
530
|
---
|
|
531
531
|
|
|
532
532
|
## k-REPL (Read-Evaluate-Print Loop)
|
|
533
533
|
|
|
534
|
-
Also there is a REPL, `k-repl` (`./node_modules/.bin/k-repl`),
|
|
535
|
-
shell for the language.
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
534
|
+
Also there is a REPL, `k-repl` (`./node_modules/.bin/k-repl`),
|
|
535
|
+
which acts like a toy shell for the language.
|
|
536
|
+
|
|
537
|
+
```k-repl
|
|
538
|
+
$ k-repl
|
|
539
|
+
Very! experimental repl shell for 'k-language'...
|
|
540
|
+
--c print aliased codes
|
|
541
|
+
--C code print 'code' definition
|
|
542
|
+
--r print relations
|
|
543
|
+
--R rel print 'rel' definition with type patterns
|
|
544
|
+
--p (--pp) pretty-print last value
|
|
545
|
+
--s (--g) reg store (get) the current value in (from) register 'reg'
|
|
546
|
+
--regs print register names
|
|
547
|
+
--l file.k load 'file.k'
|
|
548
|
+
>
|
|
549
|
+
```
|
|
546
550
|
|
|
547
551
|
---
|
|
548
552
|
|
package/TODO.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# To do list for canonical names
|
|
2
|
+
|
|
3
|
+
- [ ] Write a script to search for conflicting names
|
|
4
|
+
- [ ] Export a relation. i.e., rewrite it as a list of all
|
|
5
|
+
dependency definitions using canonical names
|
|
6
|
+
- [ ] Find a way of adding 'comments' or some way of 'tagging' the definitions
|
|
7
|
+
- [X] The definitions should be simplied by removing useless filters
|
|
8
|
+
- [X] Definitions, which are just aliases to non built-in rels should not introduce a new canonical name
|
|
9
|
+
- [ ] Can we inline some references w/o changing the canonical name?
|
|
10
|
+
|
|
11
|
+
## Simplification rules
|
|
12
|
+
|
|
13
|
+
It seems to me that after calculating input and output patterns, all
|
|
14
|
+
filters and code expressions could be replaced by just input and output
|
|
15
|
+
filters corresponding to the patterns. [DONE]
|
|
16
|
+
|
|
17
|
+
The filer variables have to be renamed for normalization if they take part of
|
|
18
|
+
the canonical name calculation. [DONE]
|
package/TYPING.md
CHANGED
|
@@ -360,6 +360,6 @@ Repeat the procedure until the type pattern graph is not changing anymore.
|
|
|
360
360
|
- [X] Redefine built-in CONS and SNOC to allign with no support for non-homogeneous lists
|
|
361
361
|
- [X] Integrate filters into typePatters (execution is not affected)
|
|
362
362
|
- [/] better type error repporting - the info exists in the pattern parent tree ... in progress
|
|
363
|
-
- [
|
|
363
|
+
- [X] Introduce a space/time bounds for type derivation
|
|
364
364
|
- [ ] Check for loops, e.g., `$x = < x f, ...>`, `$x = [x]`, `$x = {x f, ...}` -- this
|
|
365
|
-
looks a little arbitrary, but maybe this is actually an important part
|
|
365
|
+
looks a little arbitrary, but maybe this is actually an important part
|