@fraczak/k 3.1.0 → 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 +37 -28
- package/Code-derivation-tests/vector.mjs +0 -3
- package/Filters/bug.k +3 -0
- package/Filters/composing.k +15 -0
- package/Filters/filter.k +9 -0
- package/README.md +18 -15
- package/TYPING.md +8 -11
- package/codes.mjs +2 -2
- package/index.mjs +5 -4
- package/k.mjs +1 -2
- package/package.json +1 -1
- package/parser.jison +8 -4
- package/parser.mjs +44 -41
- package/patterns.mjs +72 -13
- package/pretty.mjs +100 -23
- package/repl.mjs +124 -92
- package/run.mjs +6 -11
- package/typing.mjs +173 -12
- package/INTRO.md +0 -88
- package/aaa.txt +0 -203033
- 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/typing.mjs
CHANGED
|
@@ -183,6 +183,134 @@ class TypePatternGraph {
|
|
|
183
183
|
return gNodes.filter(x => !((x in excluded) || (this.patterns.nodes[x].pattern == 'type')));
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
getCompressed() {
|
|
187
|
+
const newTypePatternGraph = new TypePatternGraph();
|
|
188
|
+
const renamed = this.cloneAll(newTypePatternGraph);
|
|
189
|
+
newTypePatternGraph.turnSingletonPatternsIntoCodes();
|
|
190
|
+
|
|
191
|
+
Object.keys(renamed).forEach( id => {
|
|
192
|
+
renamed[id] = newTypePatternGraph.find(renamed[id]);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// console.log("newTypePatternGraph", newTypePatternGraph);
|
|
196
|
+
// console.log("nodes", newTypePatternGraph.patterns.nodes);
|
|
197
|
+
// console.log("edges", newTypePatternGraph.edges);
|
|
198
|
+
|
|
199
|
+
const rootPatternIds = newTypePatternGraph.patterns.nodes.map((x,i) => i)
|
|
200
|
+
.filter(x => newTypePatternGraph.find(x) == x);
|
|
201
|
+
|
|
202
|
+
// console.log("rootPatternIds", rootPatternIds);
|
|
203
|
+
|
|
204
|
+
const equivalence = rootPatternIds.reduce( (equivalence,i) => {
|
|
205
|
+
const pattern = newTypePatternGraph.get_pattern(i);
|
|
206
|
+
switch (pattern.pattern) {
|
|
207
|
+
case 'type':
|
|
208
|
+
case '(...)':
|
|
209
|
+
case '{...}':
|
|
210
|
+
case '<...>':
|
|
211
|
+
equivalence.push([i]);
|
|
212
|
+
break;
|
|
213
|
+
default:
|
|
214
|
+
equivalence[0].push(i);
|
|
215
|
+
};
|
|
216
|
+
return equivalence;
|
|
217
|
+
}, [[]]).filter(x => x.length > 0);
|
|
218
|
+
|
|
219
|
+
const reps = equivalence.reduce( (reps,eqClass) => {
|
|
220
|
+
eqClass.forEach( x => reps[x] = eqClass);
|
|
221
|
+
return reps;
|
|
222
|
+
}, {});
|
|
223
|
+
|
|
224
|
+
// console.log("equivalence", equivalence);
|
|
225
|
+
|
|
226
|
+
const areDifferent = (i1,i2) => {
|
|
227
|
+
const p1 = newTypePatternGraph.get_pattern(i1);
|
|
228
|
+
const p2 = newTypePatternGraph.get_pattern(i2);
|
|
229
|
+
if (p1.pattern != p2.pattern) return true;
|
|
230
|
+
const e1 = newTypePatternGraph.edges[i1];
|
|
231
|
+
const e2 = newTypePatternGraph.edges[i2];
|
|
232
|
+
if (Object.keys(e1).length != Object.keys(e2).length) return true;
|
|
233
|
+
for (const lab in e1) {
|
|
234
|
+
if (e2[lab] == undefined) return true;
|
|
235
|
+
const dests1 = Object.values(e1[lab])[0];
|
|
236
|
+
const dests2 = Object.values(e2[lab])[0];
|
|
237
|
+
if (reps[dests1] != reps[dests2]) return true;
|
|
238
|
+
}
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
let changed = true;
|
|
242
|
+
while (changed) {
|
|
243
|
+
changed = false;
|
|
244
|
+
const equivalenceSize = equivalence.length;
|
|
245
|
+
for (let eqClassPos = 0; eqClassPos < equivalenceSize; eqClassPos++) {
|
|
246
|
+
const eqClass = equivalence[eqClassPos];
|
|
247
|
+
const oldClass = [eqClass[0]];
|
|
248
|
+
const newClass = [];
|
|
249
|
+
for (let i = 1; i < eqClass.length; i++) {
|
|
250
|
+
if (areDifferent(oldClass[0],eqClass[i])) {
|
|
251
|
+
newClass.push(eqClass[i]);
|
|
252
|
+
} else {
|
|
253
|
+
oldClass.push(eqClass[i]);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (newClass.length > 0) {
|
|
257
|
+
changed = true;
|
|
258
|
+
equivalence.push(newClass);
|
|
259
|
+
equivalence[eqClassPos] = oldClass;
|
|
260
|
+
for (const i of newClass) {
|
|
261
|
+
reps[i] = newClass;
|
|
262
|
+
}
|
|
263
|
+
for (const i of oldClass) {
|
|
264
|
+
reps[i] = oldClass;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// console.log("equivalence (final)", equivalence);
|
|
271
|
+
// console.log("reps", reps);
|
|
272
|
+
|
|
273
|
+
const compressedTypePatternGraph = new TypePatternGraph();
|
|
274
|
+
const newIds = {};
|
|
275
|
+
for (const eqClass of equivalence) {
|
|
276
|
+
// console.log("eqClass", eqClass);
|
|
277
|
+
const oldId = eqClass[0];
|
|
278
|
+
const pattern = newTypePatternGraph.get_pattern(oldId);
|
|
279
|
+
const newId = (() => {
|
|
280
|
+
if (pattern.pattern == 'type') return compressedTypePatternGraph.getTypeId(pattern.type);
|
|
281
|
+
return compressedTypePatternGraph.patterns.addNewNode(pattern);
|
|
282
|
+
})();
|
|
283
|
+
newIds[oldId] = newId;
|
|
284
|
+
}
|
|
285
|
+
for (const oldId in newIds) {
|
|
286
|
+
const newId = newIds[oldId];
|
|
287
|
+
const pattern = newTypePatternGraph.get_pattern(oldId);
|
|
288
|
+
const newPattern = compressedTypePatternGraph.get_pattern(newId);
|
|
289
|
+
// console.log("patterns", pattern, newPattern);
|
|
290
|
+
if (pattern.pattern == 'type')
|
|
291
|
+
continue;
|
|
292
|
+
const edges = newTypePatternGraph.edges[oldId];
|
|
293
|
+
// console.log("edges", edges);
|
|
294
|
+
compressedTypePatternGraph.edges[newId] = {};
|
|
295
|
+
for (const lab in edges) {
|
|
296
|
+
// console.log("edges[lab]", edges[lab]);
|
|
297
|
+
compressedTypePatternGraph.edges[newId][lab] = asMapSet(Object.values(edges[lab]).map(x =>
|
|
298
|
+
newIds[reps[newTypePatternGraph.find(x)][0]]));
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const remapping = Object.keys(renamed).reduce( (remapping,id) => {
|
|
303
|
+
return {...remapping, [id]: newIds[ reps[renamed[id]][0] ]};
|
|
304
|
+
}, {});
|
|
305
|
+
|
|
306
|
+
// console.log("remapping", remapping);
|
|
307
|
+
// console.log("compressedTypePatternGraph", compressedTypePatternGraph);
|
|
308
|
+
// console.log("nodes", compressedTypePatternGraph.patterns.nodes);
|
|
309
|
+
// console.log("edges", compressedTypePatternGraph.edges);
|
|
310
|
+
// console.log("--------------------")
|
|
311
|
+
return {typePatternGraph: compressedTypePatternGraph, remapping};
|
|
312
|
+
}
|
|
313
|
+
|
|
186
314
|
clone(roots,targetGraph = this) {
|
|
187
315
|
const result = {}; // mapping from original ids to cloned ids
|
|
188
316
|
const find = (x) => this.find(x);
|
|
@@ -240,7 +368,8 @@ class TypePatternGraph {
|
|
|
240
368
|
if (subsetP(p1.fields, p2.fields)) return p2;
|
|
241
369
|
throw new Error(`Cannot unify (${p1.fields},...) with (${p2.fields})`);
|
|
242
370
|
case '[]':
|
|
243
|
-
return p2;
|
|
371
|
+
if (p1.fields.every(x => `${x}`.match(/^[0-9]+$/))) return p2;
|
|
372
|
+
throw new Error(`Cannot unify [] with (${p1.fields},...)`);
|
|
244
373
|
case '{}':
|
|
245
374
|
if (subsetP(p1.fields, p2.fields)) return p2;
|
|
246
375
|
throw new Error(`Cannot unify (${p1.fields},...) with {${p2.fields}}`);
|
|
@@ -283,7 +412,8 @@ class TypePatternGraph {
|
|
|
283
412
|
if (subsetP(p1.fields, p2.fields))
|
|
284
413
|
return {pattern: '{}', fields: p2.fields};
|
|
285
414
|
case '[]':
|
|
286
|
-
return p2;
|
|
415
|
+
if (p1.fields.every(x => `${x}`.match(/^[0-9]+$/))) return p2;
|
|
416
|
+
throw new Error(`Cannot unify [] with {${p1.fields},...}`);
|
|
287
417
|
case '{}':
|
|
288
418
|
if (subsetP(p1.fields, p2.fields)) return p2;
|
|
289
419
|
throw new Error(`Cannot unify {${p1.fields},...} with {${p2.fields}}`);
|
|
@@ -319,6 +449,17 @@ class TypePatternGraph {
|
|
|
319
449
|
case 'type':{
|
|
320
450
|
const code = codes.find(p2.type);
|
|
321
451
|
switch (code.code) {
|
|
452
|
+
case 'int':
|
|
453
|
+
// supports (2 .2) which returns unit
|
|
454
|
+
if (p1.fields.every(x => `${x}`.match(/^[0-9]+$/)))
|
|
455
|
+
return p2;
|
|
456
|
+
break;
|
|
457
|
+
case 'string':
|
|
458
|
+
return p2;
|
|
459
|
+
case 'bool':
|
|
460
|
+
if (p1.fields.every(x => `${x}`.match(/^true|false$/)))
|
|
461
|
+
return p2;
|
|
462
|
+
break;
|
|
322
463
|
case 'union': {
|
|
323
464
|
let p2_fields = Object.keys(code[code.code]);
|
|
324
465
|
if (subsetP(p1.fields, p2_fields)) return {...p2, fields: p2_fields};
|
|
@@ -328,7 +469,7 @@ class TypePatternGraph {
|
|
|
328
469
|
};
|
|
329
470
|
};
|
|
330
471
|
break;
|
|
331
|
-
case '()':
|
|
472
|
+
case '()': // Pattern '()' can be introduced by filter e.g., ?(X x, Y x)
|
|
332
473
|
switch (p2.pattern) {
|
|
333
474
|
case '()':
|
|
334
475
|
if (eqsetP(p1.fields, p2.fields)) return p2;
|
|
@@ -337,18 +478,32 @@ class TypePatternGraph {
|
|
|
337
478
|
if (eqsetP(p1.fields, p2.fields)) return p2;
|
|
338
479
|
throw new Error(`Cannot unify (${p1.fields}) with {${p2.fields}}`);
|
|
339
480
|
case '[]':
|
|
340
|
-
return p2;
|
|
481
|
+
if (p1.fields.every(x => `${x}`.match(/^[0-9]+$/))) return p2;
|
|
482
|
+
throw new Error(`Cannot unify [] with (${p1.fields})`);
|
|
341
483
|
case '<>':
|
|
342
484
|
if (eqsetP(p1.fields, p2.fields)) return p2;
|
|
343
485
|
throw new Error(`Cannot unify (${p1.fields}) with <${p2.fields}>`);
|
|
344
486
|
case 'type':{
|
|
345
487
|
const code = codes.find(p2.type);
|
|
346
488
|
switch (code.code) {
|
|
489
|
+
case 'int':
|
|
490
|
+
if (p1.fields.every(x => `${x}`.match(/^[0-9]+$/)))
|
|
491
|
+
return p2;
|
|
492
|
+
break;
|
|
493
|
+
case 'string':
|
|
494
|
+
return p2;
|
|
495
|
+
case 'bool':
|
|
496
|
+
if (p1.fields.every(x => `${x}`.match(/^true|false$/)))
|
|
497
|
+
return p2;
|
|
498
|
+
break;
|
|
347
499
|
case 'product':
|
|
348
500
|
case 'union': {
|
|
349
501
|
let p2_fields = Object.keys(code[code.code]);
|
|
350
502
|
if (eqsetP(p1.fields, p2_fields)) return {...p2, fields: p2_fields};
|
|
351
|
-
}
|
|
503
|
+
}; break;
|
|
504
|
+
case 'vector':
|
|
505
|
+
if (p1.fields.every(x => `${x}`.match(/^[0-9]+$/)))
|
|
506
|
+
return {...p2, fields: ['vector-member']};
|
|
352
507
|
}
|
|
353
508
|
throw new Error(`Cannot unify ${JSON.stringify(p1)} with code ${p2.type}:${code.def}`);
|
|
354
509
|
};
|
|
@@ -356,10 +511,11 @@ class TypePatternGraph {
|
|
|
356
511
|
break;
|
|
357
512
|
case '[]':
|
|
358
513
|
switch (p2.pattern) {
|
|
359
|
-
case '[]':
|
|
360
|
-
if (eqsetP(p1.fields, p2.fields)) return p2;
|
|
361
|
-
throw new Error(`Cannot unify [${p1.fields}] with [${p2.fields}]`);
|
|
362
514
|
case '{}':
|
|
515
|
+
// if (p2.fields.every(x => `${x}`.match(/^[0-9]+$/)))
|
|
516
|
+
// return p1;
|
|
517
|
+
throw new Error(`Cannot unify [] with {${p2.fields}}`);
|
|
518
|
+
case '[]':
|
|
363
519
|
return p1;
|
|
364
520
|
case '<>':
|
|
365
521
|
throw new Error('Cannot unify [] with <>');
|
|
@@ -435,8 +591,13 @@ class TypePatternGraph {
|
|
|
435
591
|
const fields = Object.keys(this.edges[x] || {});
|
|
436
592
|
return {...pattern, fields: fields};
|
|
437
593
|
});
|
|
438
|
-
|
|
439
|
-
|
|
594
|
+
|
|
595
|
+
const new_pattern = (() => { try {
|
|
596
|
+
return {...this.unify_patterns(...rep_patters), rule : rule}
|
|
597
|
+
} catch (e) {
|
|
598
|
+
e.message = `Unification rule "${rule}"\n - ${e.message}`;
|
|
599
|
+
throw e;
|
|
600
|
+
} })();
|
|
440
601
|
const new_id = (() => {
|
|
441
602
|
if (new_pattern.pattern == 'type') {
|
|
442
603
|
const id = this.getTypeId(new_pattern.type);
|
|
@@ -524,5 +685,5 @@ class TypePatternGraph {
|
|
|
524
685
|
}
|
|
525
686
|
}
|
|
526
687
|
|
|
527
|
-
export {
|
|
528
|
-
export default {
|
|
688
|
+
export { TypePatternGraph };
|
|
689
|
+
export default { TypePatternGraph };
|
package/INTRO.md
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
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.
|