@fraczak/k 2.0.0 → 2.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/README.md CHANGED
@@ -10,31 +10,206 @@ From javascript:
10
10
  console.log([{name:"x"},{nom:"y"},{}].map(fn));
11
11
  // returns: [ "x", "y", "?" ]
12
12
 
13
- Another JSON transformation notation. A `k`-expression (script)
14
- defines a __partial function__, i.e., a function which may fail
15
- for some input. `k`-expressions can be combined to build
16
- other `k`-expressions in three ways:
13
+ ---
17
14
 
18
- 1. composition, e.g.:
15
+ ## k - the way of building and manipulating JSON-like data
19
16
 
20
- (E1 E2 E3 ...)
17
+ Technically, `k` is a notation for defining **first-order partial functions**.
21
18
 
22
- Apart from empty composition, `()`, which defines _identity_, the
23
- paranthesis can be omitted.
19
+ An example of a _partial function_ is the _projection_, e.g., "`.toto`",
20
+ which maps an object to its property named `toto`, or it is not defined if
21
+ the property doesn't exist. E.g.,
24
22
 
25
- 2. product, e.g., vector or structure:
23
+ 1 .toto :
24
+ 2 {"toto": 5, "titi": 10} --> 5
25
+ 3 {"titi": 10} ... undefined // it is not a value!
26
26
 
27
- [ E1, E2, E3, ... ]
28
- { E1 "e1", E2 "e2", E3 "e3", ... }
27
+ > Note: The above 3 lines should be read as follows. A `k`-expression
28
+ > is printed in the first line (before "`:`"). The following lines
29
+ > are examples of the function defined by the `k`-expression applayed
30
+ > to JSON values (first part of each line). If the function for the
31
+ > value is defined, then the result is printed after "`-->`" (line 2 in
32
+ > the above example). If the function is not defined for the value,
33
+ > then "`... undefined`" is printed (line 3).
29
34
 
30
- 3. union (merge), e.g.:
35
+ ---
31
36
 
32
- < E1, E2, E3, ... >
37
+ ### Combining "partial functions"
33
38
 
34
- Elementary partial functions are:
39
+ There are three ways of combining functions:
35
40
 
36
- 4. _projection_, i.e., extracting the value of a given field or
37
- index. Examples:
41
+ 1. **composition**: `(f1 f2 ...)`, e.g. `(.toto .titi)` extracts
42
+ nested field.
43
+
44
+ (.toto .titi) :
45
+ {"toto": {"titi": 10}} --> 10
46
+ {"toto": 10 } ... undefined
47
+ {} ... undefined
48
+
49
+ 2. **merge**: `< f1, f2,... >`, e.g., `<.toto, .titi>` extracts field
50
+ `toto` if present; otherwise extracts `titi`.
51
+
52
+ <.toto, .titi> :
53
+ {"toto": 5, "titi": 10} --> 5
54
+ {"titi": 10 } --> 10
55
+ {} ... undefined
56
+
57
+ 3. **product**: `{ f1 label1, f2 label2, ...}`, e.g., `{.toto TOTO,
58
+ .titi TITI}` extracts two fields and builds a record out of them.
59
+
60
+ {.toto TOTO, .titi TITI} :
61
+ {"toto": 5, "titi": 10, "x": 3} --> {"TOTO": 5, "TITI": 10}
62
+ {"titi": 10 } ... undefined
63
+
64
+ ---
65
+
66
+ **QUIZ**: What is:
67
+
68
+ - empty composition: `()` ?
69
+ - empty merge: `<>` ?
70
+ - empty product: `{}` ?
71
+ - `{{{{} s} s} s}` ?
72
+ - `({{{() a} b} c} .c .b .a)` ?
73
+
74
+ ---
75
+
76
+ ### Syntactic sugar
77
+
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.
80
+
81
+ For example, `[(.toto .titi (.0 .1))]` can be written as `[.toto.titi.0.1]`.
82
+
83
+ Comments can be introduced by `//`, `--`, `%`, or `#` and extends to
84
+ the end of line. Multiline `C`-like comments, `/* ... */`, are also
85
+ supported.
86
+
87
+ ### Basic extensions
88
+
89
+ #### Constants, i.e., literals for `strings`, `integers`, `booleans`, and `null`
90
+
91
+ A constant defines a function which ignores its argument and produces
92
+ the constant value. E.g.:
93
+
94
+ {123 int, "kScript" str, true bool, null null} :
95
+ "any" --> {"int":123,"str":"kScript","bool":true,"null":null}
96
+
97
+ Those values, i.e., `strings`, `integers`, `booleans`, and `null`, admit the
98
+ projection to the canonicat string representation of the value, e.g.:
99
+
100
+ .2 :
101
+ 2 --> {}
102
+ "2" --> {}
103
+ 4 ... undefined
104
+ true ... undefined
105
+
106
+ .true :
107
+ true --> {}
108
+ "true" --> {}
109
+ 4 ... undefined
110
+ "toto" ... undefined
111
+
112
+ .null :
113
+ null --> {}
114
+ "null" --> {}
115
+ 4 ... undefined
116
+ false ... undefined
117
+
118
+ #### Vector product
119
+
120
+ 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]`.
123
+
124
+ [.toto, .titi, 12] :
125
+ {"toto": 5, "titi": 10 } --> [5, 10, 12]
126
+
127
+ .1 :
128
+ ["A","B","C"] --> "B"
129
+ ["a"] ... undefined
130
+
131
+ ---
132
+
133
+ ### Pragmatic extensions, aka "standard library"
134
+
135
+ - `GT` -- identity for lists of decreasing elements; undefined otherwise
136
+
137
+ GT:
138
+ [4,3] --> [4,3]
139
+ [3,4] ... undefined
140
+ [] --> []
141
+ [4,3,0] --> [4,3,0]
142
+
143
+ - `EQ` -- identity for lists of equal elements; undefined otherwise
144
+
145
+ EQ:
146
+ [4,4] --> [4,4]
147
+ [4,5] ... undefined
148
+ [4,4,4] --> [4,4,4]
149
+ [] --> []
150
+
151
+ - `PLUS` and `TIMES` -- sum and product of lists of numbers
152
+
153
+ {PLUS plus, TIMES times} :
154
+ [1,2] --> {"plus":3,"times":2}
155
+ [2,2,2] --> {"plus":6,"times":8}
156
+ [] --> {"plus":0,"times":1}
157
+
158
+ - `CONCAT` -- concatenation of lists of strings
159
+
160
+ CONCAT:
161
+ ["a","bc","d"] --> "abcd"
162
+ ["a","bc","d"] --> "abcd"
163
+
164
+ - `toJSON` and `fromJSON` -- conversion to and from JSON strings
165
+
166
+ toJSON:
167
+ {"a": 12} --> "{\"a\":12}"
168
+
169
+ fromJSON:
170
+ "{\"a\":12}" --> {"a":12}
171
+ "2.12" --> 2.12
172
+ "[1,2.11,0.3e-32]" --> [1,2.11,3e-33]
173
+
174
+
175
+ - other predefined parial functions are: `DIV`, `FDIV`, `CONS`, `SNOC`, `toDateMsec`,
176
+ `toDateStr`, and `_log!`.
177
+
178
+ ---
179
+
180
+ ### Function definitions
181
+
182
+ dec = [(),-1] PLUS;
183
+ max = <SNOC [.0, .1 max] <GT.0, .1>, .0> ;
184
+ factorial = < [(),0] GT .0 [dec factorial, ()] TIMES, 1 >;
185
+
186
+ ### Codes (_types_)
187
+
188
+ _Codes_ (prefixed by `$`) can be defined by taged union and product. E.g.:
189
+
190
+ $nat = <nat 1, {} 0>;
191
+ $pair = {nat x, nat y};
192
+
193
+ suc = {$nat 1};
194
+ add = $pair <{.x.1 x, .y suc y} add, .y>;
195
+
196
+ #### Basic extension codes
197
+
198
+ Since _basic extension_ introduces integers, booleans, and strings, there are three
199
+ predefined types: `int`, `bool`, and `string`. A vector product code can also be defined
200
+ by `[ codeExp ]`. All members of the vector are the same code. E.g.,
201
+
202
+ $intVector = [ int ];
203
+ $boolVector = [ bool ];
204
+ $tree = [ tree ];
205
+
206
+ emptyList? = $intVector $[ string ]; -- as only an empty vector can be a vector
207
+ -- of integers and a vector of strings
208
+ ---
209
+
210
+ ## Examples
211
+
212
+ 1. projection:
38
213
 
39
214
  .x
40
215
  ."field name"
@@ -43,7 +218,7 @@ other `k`-expressions in three ways:
43
218
  The function is defined only if its argument is a structure with
44
219
  the field (or a vector with the index).
45
220
 
46
- 5. _constants_, literals for Strings, Booleans, and
221
+ 2. _constants_, literals for Strings, Booleans, and
47
222
  Integers. Examples:
48
223
 
49
224
  "a string"
@@ -52,14 +227,12 @@ the field (or a vector with the index).
52
227
  false
53
228
  null
54
229
 
55
- 6. The other "built-in" functions: `GT`, `EQ`, `PLUS`,
56
- `TIMES`, `DIV`, `CONCAT`, `toJSON`, `fromJSON`, `CONS`,
57
- `SNOC`, `toDateMsec`, `toDateStr`, and `_log!`. For example:
230
+ 3. "built-in" functions:
58
231
 
59
- [1, 2, 3] PLUS --> integer constant function 6
60
- [4, 4] TIMES toJSON --> string constant function "16"
61
- [3, 2] GT --> vector constant function [3, 2]
62
- [3, 4] GT ... is not defined!
232
+ [1, 2, 3] PLUS -- integer constant function 6
233
+ [4, 4] TIMES toJSON -- string constant function "16"
234
+ [3, 2] GT -- vector constant function [3, 2]
235
+ [3, 4] GT -- ... undefined
63
236
 
64
237
  A more interesting example could be:
65
238
 
@@ -69,7 +242,7 @@ the field (or a vector with the index).
69
242
 
70
243
  [3,8] < GT .0, .1 > --> 8
71
244
 
72
- ## User defined functions
245
+ ### User defined functions
73
246
 
74
247
  `k`-expression can be prefixed by function definitions. E.g.:
75
248
 
@@ -84,22 +257,22 @@ the field (or a vector with the index).
84
257
  Another example could be finding the biggest (max) value in a vector:
85
258
 
86
259
  max = <
87
- SNOC -- [x0, x1, x2, ...] -> [x0, [x1, x2, ...]]
88
- [.0, .1 max] -- [x0, [x1, x2, ...]] -> [x0, max(x1,x2,...)], i.e., recursive call
89
- <GT .0, .1>, -- if x0 > max(x1,x2,...) then x0 else max(x1,x2,...)
90
- -- when SNOC is not defined, e.g. the argument is a singleton vector [x0]
91
- .0 -- [x0] -> x0,
260
+ SNOC # [x0, x1, x2, ...] --> [x0, [x1, x2, ...]]
261
+ [.0, .1 max] # [x0, [x1, x2, ...]] --> [x0, max(x1,x2,...)], i.e., recursive call
262
+ <GT .0, .1> # if x0 > max(x1,x2,...) then x0 else max(x1,x2,...)
263
+ , # when SNOC is not defined, i.e., if the input vector has one element:
264
+ .0 # [x0] --> x0
92
265
  >;
93
266
  max
94
267
 
95
- ## Value encodings (_codes_)
268
+ ### Value encodings (_codes_)
96
269
 
97
270
  There are three predefined value encodings: `int`, `string`, and
98
271
  `bool`. The language supports `code`-expressions:
99
272
 
100
- * product, e.g., `{int x, int y, bool flag}`
101
- * disjoint union, e.g., `<{} true, {} false>`
102
- * vector, e.g., `[ int ]` (all elements of the vector use the same
273
+ - product, e.g., `{int x, int y, bool flag}`
274
+ - disjoint union, e.g., `<{} true, {} false>`
275
+ - vector, e.g., `[ int ]` (all elements of the vector use the same
103
276
  encoding)
104
277
 
105
278
  One can define recursive codes. E.g.:
@@ -121,34 +294,38 @@ within `k`-expression is again prefixed by `$`.
121
294
  > $ int;
122
295
  height
123
296
 
124
- ## Command line script
297
+ ---
298
+
299
+ ## `k` (a command-line JSON processor using `k` syntax)
125
300
 
126
- There is a wrapper, `./node_modules/.bin/k` , which makes it easy to
301
+ There is a wrapper, `k` (`./node_modules/.bin/k`), which makes it easy to
127
302
  run the language from command line.
128
303
 
129
- > ./node_modules/.bin/k
130
- ... errors ...
304
+ > k
305
+ ... errors ...
131
306
  Usage: ./node_modules/.bin/k ( k-expr | -k k-file) [ -1 ] [ json-file ]
132
307
  E.g., cat '{"a": 10}' | ./node_modules/.bin/k '[(),()]'
133
308
 
134
- ### Examples
309
+ For example:
135
310
 
136
311
  1. One `k`-expression with one `json`-object:
137
312
 
138
- > echo '{"x": 12, "y": 13}' | ./k.coffee '{ <.x, "no x"> x, () input}'
313
+ > echo '{"x": 12, "y": 13}' | k '{ <.x, "no x"> x, () input}'
139
314
  {"x":12,"input":{"x":12,"y":13}}
140
315
 
141
316
  2. By providing only `k`-expression, the script will compile the
142
317
  `k`-expression and apply the generated function to the `stdin`,
143
318
  line by line:
144
319
 
145
- > ./node_modules/.bin/k '<["x=",.x," & y=",.y],["only x=",.x],["only y=",.y],["no x nor y"]>{CONCAT "x&y"}'
320
+ > k '<["x=",.x," & y=",.y],["only x=",.x],["only y=",.y],["no x nor y"]>{CONCAT "x&y"}'
146
321
 
147
322
  {"y": 123, "x": 432,"others": "..."} --> {"x&y":"x=432 & y=123"}
148
323
  {"x": 987} --> {"x&y":"only x=987"}
149
324
  {"z": 123} --> {"x&y":"no x nor y"}
150
325
  ^D - to interrupt
151
326
 
327
+ If the input is a multiline json object, we need to add `-1` to the command-line options.
328
+
152
329
  3. If the `k`-expression is long, it can be put in a file, e.g.:
153
330
 
154
331
  > cat test.k
@@ -168,11 +345,11 @@ run the language from command line.
168
345
 
169
346
  We can use it by:
170
347
 
171
- > ./node_modules/.bin/k -k test.k
348
+ > k -k test.k
172
349
 
173
350
  If we want to read `json` objects from a file, e.g., `my-objects.json`, we do
174
351
 
175
- > ./node_modules/.bin/k -k test.k my-objects.json
352
+ > k -k test.k my-objects.json
176
353
  {"x&y":"x=432 & y=123"}
177
354
  {"x&y":"only x=987"}
178
355
  {"x&y":"no x nor y"}
@@ -187,9 +364,38 @@ run the language from command line.
187
364
  {"z": 123}
188
365
  ####################################################
189
366
 
190
- ### k-REPL (Read-Evaluate-Print Loop)
191
-
192
- Also there is a REPL, `./node_modules/.bin/k-repl`, which acts like a toy
367
+ ---
368
+
369
+ ### Short comparaison with `jq` tutorial examples: <https://stedolan.github.io/jq/tutorial/>
370
+
371
+ 1.
372
+ curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | jq '.'
373
+ curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | k '()' -1
374
+ 2.
375
+ curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | jq '.[0]'
376
+ curl 'https://api.github.com/repositories/5101141/commits?per_page=5' | k '.0' -1
377
+ 3.
378
+ jq '.[0] | {message: .commit.message, name: .commit.committer.name}'
379
+ k '.0 {.commit.message message, .commit.committer.name name}' -1
380
+ 4. note: `k`-expression defines a partial function yielding a single json object, i.e., as far as `k` is concerned,
381
+ examples 4 and 5 of the `jq` tutorial are equivalent.
382
+ 5.
383
+ jq '[.[] | {message: .commit.message, name: .commit.committer.name}]'
384
+ k 'f = .commit {.message message, .committer.name name}; %\
385
+ map_f = <SNOC [.0 f,.1 map_f] CONS, [.0 f], []>; %\
386
+ map_f' -1
387
+ 6.
388
+ jq '[.[] | {message: .commit.message, name: .commit.committer.name, parents: [.parents[].html_url]}]'
389
+ k 'map_html_url = <SNOC [.0 .html_url, .1 map_html_url] CONS, [.0 .html_url], []>; %\
390
+ f = {.commit.message message, .commit.committer.name name, .parents map_html_url parents}; %\
391
+ map_f = <SNOC [.0 f, .1 map_f] CONS, [.0 f] , []>; %\
392
+ map_f' -1
393
+
394
+ ---
395
+
396
+ ## k-REPL (Read-Evaluate-Print Loop)
397
+
398
+ Also there is a REPL, `k-repl` (`./node_modules/.bin/k-repl`), which acts like a toy
193
399
  shell for the language. E.g.:
194
400
 
195
401
  > ./node_modules/.bin/k-repl
@@ -202,11 +408,13 @@ shell for the language. E.g.:
202
408
  inc inc inc inc
203
409
  => 7
204
410
 
205
- ## Using from `javascript`
411
+ ---
412
+
413
+ ## Using `k` from `javascript`
206
414
 
207
- var k = require("k");
415
+ import k from "@fraczak/k";
208
416
 
209
- k_expression = '()';
417
+ let k_expression = '()';
210
418
  k.run(k_expression,"ANYTHING...");
211
419
  // RETURNS: "ANYTHING..."
212
420
 
@@ -249,7 +457,7 @@ shell for the language. E.g.:
249
457
  k_fn({"age":2,"name":"Mark"});
250
458
  // RETURNS: {"nom":"Mark","age":"enfant"}
251
459
 
252
- var k_fn = k.compile('$t = < i: int, t: [ t ] > ; <$t, $int>');
460
+ k_fn = k.compile('$t = < i: int, t: [ t ] > ; <$t, $int>');
253
461
 
254
462
  k_fn(1);
255
463
  // RETURNS: 1
@@ -263,7 +471,7 @@ shell for the language. E.g.:
263
471
  k_fn({"t":[{"i":2},{"i":3},{"t":[]}]});
264
472
  // RETURNS: {"t":[{"i":2},{"i":3},{"t":[]}]}
265
473
 
266
- var k_fn = k.compile('$ < < [ int ] ints, [ bool ] bools > list, string None>');
474
+ k_fn = k.compile('$ < < [ int ] ints, [ bool ] bools > list, string None>');
267
475
 
268
476
  k_fn({"None":"None"});
269
477
  // RETURNS: {"None":"None"}
package/codes.mjs CHANGED
@@ -78,7 +78,6 @@ function normalizeAll(codes, representatives) {
78
78
  return Object.keys(codes).reduce(function (normalized, name) {
79
79
  if (name === representatives[name]) {
80
80
  const code = codes[name];
81
-
82
81
  switch (code.code) {
83
82
  case "union":
84
83
  case "product":
package/index.mjs CHANGED
@@ -1,7 +1,5 @@
1
1
  import { parse } from "./parser.mjs";
2
-
3
2
  import run from "./run.mjs";
4
-
5
3
  import t from "./codes.mjs";
6
4
 
7
5
  function finalize(codes) {
@@ -31,5 +29,4 @@ function runScriptOnData(script, data) {
31
29
  runScriptOnData.doc = "Run 'script' (string) on 'data': (script,data) -> data";
32
30
 
33
31
  export default { compile, run: runScriptOnData, parse };
34
-
35
32
  export { compile, runScriptOnData as run, parse };
package/k.mjs CHANGED
@@ -9,7 +9,7 @@ const prog = process.argv[1];
9
9
 
10
10
  let kScript, jsonStream, oneJson;
11
11
 
12
- ({ kScript, jsonStream, oneJson } = (function (oneJson, args) {
12
+ ({ kScript, jsonStream, oneJson } = ((oneJson, args) => {
13
13
  let e;
14
14
  try {
15
15
  kScript = (function (arg) {
@@ -44,49 +44,36 @@ let kScript, jsonStream, oneJson;
44
44
  })(false, process.argv.slice(2)));
45
45
 
46
46
  if (oneJson) {
47
- (function (buffer) {
48
- jsonStream.on("data", function (data) {
49
- return buffer.push(data);
50
- });
51
- return jsonStream.on("end", function () {
52
- var e;
53
- try {
54
- return console.log(
55
- JSON.stringify(kScript(JSON.parse(buffer.join(""))))
56
- );
57
- } catch (error) {
58
- e = error;
59
- return console.error(e);
60
- }
61
- });
62
- })([]);
47
+ const buffer = [];
48
+ jsonStream.on("data", (data) => buffer.push(data));
49
+ jsonStream.on("end", () => {
50
+ try {
51
+ console.log(JSON.stringify(kScript(JSON.parse(buffer.join(""))), null, 2));
52
+ } catch (error) {
53
+ console.error(error);
54
+ }
55
+ });
63
56
  } else {
64
- (function (buffer, line) {
65
- return jsonStream.on("data", function (data) {
66
- var e, first, i, json, last, len, ref, rest, results, todo;
67
- [first, ...rest] = data.toString("utf8").split("\n");
68
- buffer.push(first);
69
- if (rest.length > 0) {
70
- todo = buffer.join("");
71
- (ref = rest), ([...rest] = ref), ([last] = splice.call(rest, -1));
72
- buffer = [last];
73
- todo = [todo, ...rest];
74
- results = [];
75
- for (i = 0, len = todo.length; i < len; i++) {
76
- json = todo[i];
77
- if (!json.match(/^[ \n\t]*(?:#.*)?$/)) {
78
- try {
79
- console.log(JSON.stringify(kScript(JSON.parse(json))));
80
- } catch (error) {
81
- e = error;
82
- console.error(`Problem [line ${line}]: '${json}'`);
83
- console.error(e);
84
- }
57
+ let buffer = [];
58
+ let line = 0;
59
+ jsonStream.on("data", (data) => {
60
+ const [first, ...rest] = data.toString("utf8").split("\n");
61
+ buffer.push(first);
62
+ if (rest.length > 0) {
63
+ const todo = buffer.join("");
64
+ const last = rest.pop();
65
+ buffer = [last];;
66
+ for (const exp of [todo, ...rest]) {
67
+ if (!exp.match(/^[ \n\t]*(?:#.*)?$/)) {
68
+ try {
69
+ console.log(JSON.stringify(kScript(JSON.parse(exp))));
70
+ } catch (error) {
71
+ console.error(`Problem [line ${line}]: '${exp}'`);
72
+ console.error(error);
85
73
  }
86
- results.push((line = line + 1));
87
74
  }
88
- return results;
75
+ line++;
89
76
  }
90
- });
91
- })([], 0);
77
+ }
78
+ });
92
79
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fraczak/k",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "k-language for JSON-like data transformation",
5
5
  "main": "index.mjs",
6
6
  "scripts": {
package/run.mjs CHANGED
@@ -101,6 +101,11 @@ function run(exp, value) {
101
101
  }
102
102
  return builtin[exp.ref](value);
103
103
  case "dot":
104
+ // a hack to allow something like 'null . null' or '0 . 0' to work by returning unit
105
+ if (value === null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
106
+ if (`${value}` === `${exp.dot}`) return {};
107
+ return;
108
+ }
104
109
  return value[exp.dot];
105
110
  case "comp":
106
111
  return exp.comp.reduce((value, exp) => {
package/INTRO.md DELETED
@@ -1,160 +0,0 @@
1
- # k - the way of building and manipulating JSON-like data
2
-
3
- Technically, `k` is a notation for defining __first-order partial functions__.
4
-
5
- An example of a _partial function_ is the _projection_, e.g., "`.toto`",
6
- which maps an object to its property named `toto`, or it is not defined if
7
- the property doesn't exist. E.g.,
8
-
9
- .toto :
10
- {"toto": 5, "titi": 10} --> 5
11
- {"titi": 10} ... undefined // it is not a value!
12
-
13
- ---
14
-
15
- ## Combining "partial functions"
16
-
17
- There are three ways of combining functions:
18
-
19
- 1. __composition__: `(f1 f2 ...)`, e.g. `(.toto .titi)` extracts
20
- nested field.
21
-
22
- (.toto .titi) :
23
- {"toto": {"titi": 10}} --> 10
24
- {"toto": 10 } ... undefined
25
- {} ... undefined
26
-
27
- 2. __merge__: `< f1, f2,... >`, e.g., `<.toto, .titi>` extracts field
28
- `toto` if present; otherwise extracts `titi`.
29
-
30
- <.toto, .titi> :
31
- {"toto": 5, "titi": 10} --> 5
32
- {"titi": 10 } --> 10
33
- {} ... undefined
34
-
35
- 3. __product__: `{ f1 label1, f2 label2, ...}`, e.g., `{.toto TOTO,
36
- .titi TITI}` extracts two fields and builds a record out of them.
37
-
38
- {.toto TOTO, .titi TITI} :
39
- {"toto": 5, "titi": 10} --> {"TOTO": 5, "TITI": 10}
40
- {"titi": 10 } ... undefined
41
-
42
- ---
43
-
44
- __QUIZ__: What is:
45
-
46
- - empty composition: `()` ?
47
- - empty merge: `<>` ?
48
- - empty product: `{}` ?
49
- - `{{{{} s} s} s}` ?
50
- - `({{{() a} b} c} .c .b .a)` ?
51
-
52
- ---
53
-
54
- #### Syntactic sugar:
55
-
56
- - parenthesis can be omitted, except for the empty composition `()`,
57
- - dot (`.`) in "projection" acts as a separator so the space around it can be omitted.
58
-
59
- For example, `[(.toto .titi (.0 .1))]` can be written as `[.toto.titi.0.1]`.
60
-
61
-
62
- ## Basic extensions
63
-
64
- ### Constants, i.e., literals for `strings`, `integers`, `booleans`, and `null`
65
-
66
- A constant defines a function which ignores its argument and produces
67
- the constant value. E.g.:
68
-
69
- {123 int, "kScript" str, true bool, null null} :
70
- <any> --> {"int":123,"str":"kScript","bool":true,"null":null}
71
-
72
- ### Vector product
73
-
74
- Vector product can be used as an abbreviation for product whose field
75
- names are integers starting from zero. E.g., `{.toto "0", .titi "1",
76
- 123 "2"}` can be written as `[.toto, .titi, 123]`.
77
-
78
- [.toto, .titi, 12] :
79
- {"toto": 5, "titi": 10 } --> [5, 10, 12] // {"0":5,"1":10,"2":12}
80
-
81
- .1 :
82
- ["A","B","C"] --> "B"
83
- ["a"] ... undefined
84
- ---
85
-
86
- ## Pragmatic extensions, aka "standard library"
87
-
88
- - `GT` : -- identity for lists of decreasing elements; undefined otherwise
89
-
90
- [4,3] --> [4,3]
91
- [3,4] ... undefined
92
- [] --> []
93
- [4,3,0] --> [4,3,0]
94
-
95
- - `EQ` : -- identity for lists of equal elements; undefined otherwise
96
-
97
- [4,4] --> [4,4]
98
- [4,5] ... undefined
99
- [4,4,4] --> [4,4,4]
100
- [] --> []
101
-
102
- - `{PLUS plus, TIMES times}` :
103
-
104
- [1,2] --> {"plus":3,"times":2}
105
- [2,2,2] --> {"plus":6,"times":8}
106
- [] --> {"plus":0,"times":1}
107
-
108
- - `CONCAT` :
109
-
110
- ["a","bc","d"] --> "abcd"
111
-
112
- - `toJSON` :
113
-
114
- {"a": 12} --> "{\"a\":12}"
115
-
116
- - `fromJSON` :
117
-
118
- "{\"a\":12}" --> {"a":12}
119
-
120
- - other predefined parial functions are: `DIV`, `FDIV`, `CONS`, `SNOC`, `toDateMsec`,
121
- `toDateStr`, and `_log!`.
122
-
123
- ---
124
-
125
- ## Recursive definitions
126
-
127
- -- factorial.k
128
- dec = [(),-1] PLUS;
129
- zero? = [(),0] EQ 0;
130
- factorial = <
131
- zero? 1,
132
- [dec factorial, ()] TIMES
133
- >;
134
- { () x, factorial "x!" }
135
-
136
- ## Codes (_types_)
137
-
138
- _Codes_ (prefixed by `$`) can be defined by taged union and product. E.g.:
139
-
140
- $nat = <nat 1, {} 0>;
141
- $pair = {nat x, nat y};
142
-
143
- suc = {$nat 1};
144
- add = $pair <{.x.1 x, .y suc y} add, .y>;
145
-
146
- ### Basic extension codes
147
-
148
- Since _basic extension_ introduces integers, booleans, and strings, there are three
149
- predefined types: `int`, `bool`, and `string`. A vector product code can also be defined
150
- by `[ codeExp ]`. All members of the vector are the same code. E.g.,
151
-
152
- $intVector = [ int ];
153
- $boolVector = [ bool ];
154
- $tree = [ tree ];
155
-
156
- emptyList? = $intVector $[ string ]; -- as only an empty vector can be a vector
157
- -- of integers and a vector of strings
158
-
159
-
160
-