@fraczak/k 6.10.4 → 6.10.6
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/CHANGELOG.md +64 -0
- package/Examples/arithmetics.k +222 -110
- package/Examples/poly.k +14 -5
- package/browser/repl-browser.mjs +40 -22
- package/browser/shims/fs.mjs +2 -0
- package/browser/vfs-data.mjs +8 -11
- package/core.k +6 -78
- package/harness/suites/poly.mjs +1 -1
- package/package.json +1 -1
- package/repl-codecs.mjs +6 -3
- package/scripts/build-repl-html.mjs +6 -6
- package/scripts/perf-poly.mjs +1 -1
- package/tests/test-arithmetics.mjs +96 -0
- package/tests/test-repl-html.mjs +92 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,70 @@ All notable changes to this project will be documented here.
|
|
|
5
5
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
6
|
This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [6.10.6] — 2026-10-08 — Minimal Core Schema and REPL VFS Uploads
|
|
9
|
+
|
|
10
|
+
### Core Schema & Language
|
|
11
|
+
|
|
12
|
+
- **Minimal `core.k` Schema**:
|
|
13
|
+
- Streamlined `core.k` to focus strictly on structural type schemas
|
|
14
|
+
and pattern foundations.
|
|
15
|
+
- Removed legacy bit arithmetic (`succ`, `plus`, `times`, constants
|
|
16
|
+
`2`..`10`, and helpers `inv`, `concat`), achieving a 39% reduction
|
|
17
|
+
in file size.
|
|
18
|
+
- Retained `$bit`, `$bits`, `_`, `0`, `1`, `$string`, `$unicode`, and
|
|
19
|
+
`$pattern` definitions intact for type derivation and codecs.
|
|
20
|
+
|
|
21
|
+
### Web REPL & VFS
|
|
22
|
+
|
|
23
|
+
- **VFS Namespace Flattening**:
|
|
24
|
+
- Flattened VFS back to root filenames (`int.mjs`, `json.mjs`,
|
|
25
|
+
`utf8.mjs`, `unit.mjs`, `ieee.mjs`), ensuring consistent resolution
|
|
26
|
+
across browser and CLI environments.
|
|
27
|
+
- **Upload File Directly to VFS**:
|
|
28
|
+
- Updated "Upload" action to strictly add uploaded files into the VFS
|
|
29
|
+
without auto-loading or evaluating them as K code.
|
|
30
|
+
- Enables uploading JavaScript codecs, JSON payloads, and test vectors.
|
|
31
|
+
- Expanded file picker `accept` filter to allow `.mjs`, `.js`, and
|
|
32
|
+
`.json` files.
|
|
33
|
+
- Supported `:codec load` for `.js` codecs in the VFS explorer modal.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## [6.10.5] — 2026-10-08 — Adaptive Division and VFS Codecs
|
|
38
|
+
|
|
39
|
+
### Arithmetic & Algorithms
|
|
40
|
+
|
|
41
|
+
- **Adaptive Hybrid Division (`Examples/arithmetics.k`)**:
|
|
42
|
+
- Implemented hybrid integer division that dynamically chooses between
|
|
43
|
+
down-shift division ($|x| < 2|y|$) and restoring long division
|
|
44
|
+
($|x| \ge 2|y|$).
|
|
45
|
+
- Down-shift division scales divisor $y$ up to match length of $x$,
|
|
46
|
+
performing trial subtraction and down-shifting in $O(1)$ per step.
|
|
47
|
+
- Crossover condition is evaluated structurally in $O(\min(|y|, |x|/2))$
|
|
48
|
+
without prior length computations.
|
|
49
|
+
- Added native number-theory operations: `mod`, Euclidean `gcd`, and
|
|
50
|
+
`lcm`.
|
|
51
|
+
- Refactored `arithmetics.k` to focus purely on arithmetic operations.
|
|
52
|
+
|
|
53
|
+
### Polymorphic Lists
|
|
54
|
+
|
|
55
|
+
- **Polymorphic List Library (`Examples/poly.k`)**:
|
|
56
|
+
- Encapsulated list constructors and destructors (`list?`, `nil`,
|
|
57
|
+
`cons`, `car`, `cdr`, `singleton`, `nil?`) directly in `poly.k`.
|
|
58
|
+
- Updated benchmark suites (`harness/suites/poly.mjs`,
|
|
59
|
+
`scripts/perf-poly.mjs`) to import only arithmetic symbols from
|
|
60
|
+
`arithmetics.k`.
|
|
61
|
+
|
|
62
|
+
### Web REPL & Codecs
|
|
63
|
+
|
|
64
|
+
- **VFS Codec Subfolder Organization**:
|
|
65
|
+
- Reorganized all codec files in the Virtual File System under the
|
|
66
|
+
`codecs/` subfolder (`codecs/int.mjs`, `codecs/json.mjs`, etc.).
|
|
67
|
+
- Added backward-compatible resolution in `repl-codecs.mjs`.
|
|
68
|
+
- Added `karatsuba-mult.k` to the VFS and example picker in `repl.html`.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
8
72
|
## [6.10.4] — 2026-10-06 — Karatsuba Multiplication, Multi-Backend Harness, and CLI Help
|
|
9
73
|
|
|
10
74
|
### Arithmetic & Algorithms
|
package/Examples/arithmetics.k
CHANGED
|
@@ -4,14 +4,6 @@ swap_yes_no = < /yes |no, /no |yes > $yes_no;
|
|
|
4
4
|
yes = {}|yes $yes_no;
|
|
5
5
|
no = yes swap_yes_no;
|
|
6
6
|
|
|
7
|
-
list? = ?< {} nil, {X car, Y cdr} cons > = Y;
|
|
8
|
-
nil = {}|nil list?;
|
|
9
|
-
singleton = {() car, nil cdr} |cons list?;
|
|
10
|
-
cons = {.car car, .cdr cdr} |cons list?;
|
|
11
|
-
nil? = list? / nil nil;
|
|
12
|
-
car = list? /cons .car;
|
|
13
|
-
cdr = list? /cons .cdr;
|
|
14
|
-
|
|
15
7
|
$ bits = < {} _, bits 0, bits 1 >;
|
|
16
8
|
|
|
17
9
|
0b = {} | _;
|
|
@@ -70,29 +62,10 @@ inOrder_ = ${bits x, bits y, yes_no inOrder}
|
|
|
70
62
|
|
|
71
63
|
GT = {inOrder /no if, () then} . then;
|
|
72
64
|
|
|
73
|
-
EQ =
|
|
74
|
-
|
|
75
|
-
toBitList = {inv x, nil r} _toBitList;
|
|
76
|
-
_toBitList = <
|
|
77
|
-
{.x empty? if, .r then}.then,
|
|
78
|
-
<
|
|
79
|
-
{.x /0 x, {0 car, .r cdr} cons r},
|
|
80
|
-
{.x /1 x, {1 car, .r cdr} cons r}
|
|
81
|
-
> _toBitList
|
|
82
|
-
>;
|
|
83
|
-
fromBitList = {() l, 0b r} _fromBitList inv $bits;
|
|
84
|
-
_fromBitList =
|
|
85
|
-
<
|
|
86
|
-
{.l nil? if, .r then} .then,
|
|
87
|
-
<
|
|
88
|
-
{.l car /0 if, {.l cdr l, .r |0 r} then} .then,
|
|
89
|
-
{.l car /1 if, {.l cdr l, .r |1 r} then} .then
|
|
90
|
-
> _fromBitList
|
|
91
|
-
>;
|
|
65
|
+
EQ = {inOrder /yes if, {.x y, .y x} inOrder /yes and, () then} .then;
|
|
92
66
|
|
|
93
67
|
--------------------------------------
|
|
94
68
|
$ int = < bits '+', bits '-' >;
|
|
95
|
-
$ ints = <{int car, ints cdr} cons, {} nil>;
|
|
96
69
|
|
|
97
70
|
remove_leading_zeros = <
|
|
98
71
|
/0 remove_leading_zeros,
|
|
@@ -102,7 +75,7 @@ nat = remove_leading_zeros <empty? 0, ()>;
|
|
|
102
75
|
int = nat | '+' $int;
|
|
103
76
|
abs = $int </'+',/'-'>;
|
|
104
77
|
|
|
105
|
-
pos? = $int {
|
|
78
|
+
pos? = $int {/'+' remove_leading_zeros /1 if, () then} .then;
|
|
106
79
|
neg? = $int {/'-' if, () then} .then;
|
|
107
80
|
zero_int? = $int {/'+' /0 empty? if, () then} .then;
|
|
108
81
|
minus_one? = $int {/'-' /1 empty? if, () then} .then;
|
|
@@ -125,12 +98,12 @@ dec = $int <
|
|
|
125
98
|
/'-' {inv x, 0b y} _inc nat |'-'
|
|
126
99
|
> $int;
|
|
127
100
|
|
|
128
|
-
_dec =
|
|
101
|
+
_dec = ${bits x, bits y} <
|
|
129
102
|
{.x /1 x, .y |0 y} concat_,
|
|
130
103
|
{.x /0 x, .y |1 y} _dec
|
|
131
|
-
|
|
104
|
+
>;
|
|
132
105
|
|
|
133
|
-
$carry = <{} 0, {} 1>;
|
|
106
|
+
$ carry = <{} 0, {} 1>;
|
|
134
107
|
c0 = {}|0 $carry;
|
|
135
108
|
c1 = {}|1 $carry;
|
|
136
109
|
|
|
@@ -218,7 +191,7 @@ times = ${int x, int y}
|
|
|
218
191
|
sign_minus
|
|
219
192
|
> sign,
|
|
220
193
|
{
|
|
221
|
-
|
|
194
|
+
0b result,
|
|
222
195
|
.x abs inv _x,
|
|
223
196
|
.y abs y
|
|
224
197
|
} _times result
|
|
@@ -249,105 +222,244 @@ _times =
|
|
|
249
222
|
;
|
|
250
223
|
|
|
251
224
|
|
|
252
|
-
mod =
|
|
253
|
-
${bits x, bits y}
|
|
254
|
-
-- _log!
|
|
255
|
-
<
|
|
256
|
-
-- if y > x then (x mod y) = x
|
|
257
|
-
{.y x, .x y} GT .y,
|
|
258
|
-
-- else, i.e.
|
|
259
|
-
-- if x >= y then (x mod y) = ((x-y mod 2y) mod y)
|
|
260
|
-
{
|
|
261
|
-
{
|
|
262
|
-
{.x int x, .y int y} minus /"+" x,
|
|
263
|
-
.y inv |0 inv y
|
|
264
|
-
} mod x,
|
|
265
|
-
.y y
|
|
266
|
-
} mod
|
|
267
|
-
>
|
|
268
|
-
;
|
|
269
225
|
|
|
270
226
|
|
|
271
|
-
// gratest common divisor
|
|
272
|
-
gcd = ${bits x, bits y}
|
|
273
|
-
<
|
|
274
|
-
{.y x, .x y} GT,
|
|
275
|
-
()
|
|
276
|
-
> _gcd
|
|
277
|
-
;
|
|
278
227
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
228
|
+
// ----------------------------------------------------------------------
|
|
229
|
+
// Integer Division: Adaptive Hybrid Algorithm
|
|
230
|
+
//
|
|
231
|
+
// Combines two complementary strategies based on the bit-length
|
|
232
|
+
// comparison between dividend x and divisor y (|x| vs |y|):
|
|
233
|
+
//
|
|
234
|
+
// 1. Down-Shift Division (|x| < 2|y|, y is large relative to x):
|
|
235
|
+
// - Scales y up to y_max = y * 2^k to match length(x) via 'y inv'
|
|
236
|
+
// and prepending k zeros (|0).
|
|
237
|
+
// - In each step: trial subtraction x = x - y_scaled, then down-shifts
|
|
238
|
+
// y_scaled by 1 bit in O(1) by popping the outer zero (/_0).
|
|
239
|
+
// - Runs in exactly (|x| - |y| + 1) iterations. When y ~= x, this
|
|
240
|
+
// terminates in 1-2 steps rather than looping through all bits of x.
|
|
241
|
+
//
|
|
242
|
+
// 2. Restoring Division (|x| >= 2|y|, y is small relative to x):
|
|
243
|
+
// - Consumes bits of x from MSB to LSB into remainder accumulator r.
|
|
244
|
+
// - Remainder r stays small (r <= 2y), so trial subtractions operate
|
|
245
|
+
// on tiny numbers of length |y| rather than full-length |x|.
|
|
246
|
+
//
|
|
247
|
+
// The crossover condition |x| < 2|y| is evaluated structurally in
|
|
248
|
+
// O(min(|y|, |x|/2)) by consuming 2 bits of x for every 1 bit of y.
|
|
249
|
+
// ----------------------------------------------------------------------
|
|
250
|
+
|
|
251
|
+
// Helpers for Restoring Division (shift-and-subtract)
|
|
252
|
+
shift_in_0 = inv |0 inv nat;
|
|
253
|
+
shift_in_1 = inv |1 inv nat;
|
|
254
|
+
sub_bits = ${bits x, bits y} {.x inv x, .y inv y, c0 c} _minus inv nat;
|
|
255
|
+
|
|
256
|
+
_div_restoring =
|
|
257
|
+
${bits x, bits y, bits r, bits q}
|
|
258
|
+
<
|
|
259
|
+
{.x empty? if, {.q inv int div, .r rem} then} .then,
|
|
260
|
+
<
|
|
261
|
+
{.x /0 x, .r shift_in_0 r, .y y, .q q},
|
|
262
|
+
{.x /1 x, .r shift_in_1 r, .y y, .q q}
|
|
263
|
+
>
|
|
264
|
+
{
|
|
265
|
+
.x x,
|
|
266
|
+
.y y,
|
|
267
|
+
.q q,
|
|
268
|
+
.r r,
|
|
269
|
+
{.y x, .r y} inOrder test
|
|
270
|
+
}
|
|
271
|
+
<
|
|
272
|
+
{.test /yes if, {.x x, .y y, .q |1 q, {.r x, .y y} sub_bits r} then} .then,
|
|
273
|
+
{.test /no if, {.x x, .y y, .q |0 q, .r r} then} .then
|
|
274
|
+
>
|
|
275
|
+
_div_restoring
|
|
276
|
+
>;
|
|
283
277
|
|
|
278
|
+
// Helpers for Down-Shift Division (align and shift divisor down)
|
|
279
|
+
// Phase 1: pad _y with |0 to match length of x, counting shift steps
|
|
280
|
+
_pad_down = ${bits x, bits _y, bits steps}
|
|
281
|
+
<
|
|
282
|
+
{.x empty? if, {._y _y, .steps steps} then} .then,
|
|
283
|
+
{
|
|
284
|
+
.x </0, /1> x,
|
|
285
|
+
._y |0 _y,
|
|
286
|
+
.steps |0 steps
|
|
287
|
+
} _pad_down
|
|
288
|
+
>;
|
|
284
289
|
|
|
290
|
+
_align_down = ${bits x, bits y, bits _y}
|
|
291
|
+
<
|
|
292
|
+
// Both x and y have bits remaining: advance both
|
|
293
|
+
{
|
|
294
|
+
.x </0, /1> x,
|
|
295
|
+
.y </0, /1> y,
|
|
296
|
+
._y _y
|
|
297
|
+
} _align_down,
|
|
285
298
|
|
|
286
|
-
//
|
|
299
|
+
// y is empty while x remains: pad _y with shift zeros
|
|
300
|
+
{
|
|
301
|
+
.y empty? if,
|
|
302
|
+
{.x x, ._y _y, 0b steps} _pad_down then
|
|
303
|
+
} .then,
|
|
287
304
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
305
|
+
// Both x and y are empty: lengths equal (0 shift steps)
|
|
306
|
+
{
|
|
307
|
+
.x empty? if,
|
|
308
|
+
.y empty? and,
|
|
309
|
+
{._y _y, 0b steps} then
|
|
310
|
+
} .then
|
|
311
|
+
>;
|
|
293
312
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
{
|
|
297
|
-
|
|
313
|
+
// Phase 2: down-shift trial subtraction
|
|
314
|
+
_div_down = ${bits x, bits _y, bits steps, bits q}
|
|
315
|
+
{
|
|
316
|
+
.x x,
|
|
317
|
+
._y _y,
|
|
318
|
+
.steps steps,
|
|
319
|
+
.q q,
|
|
320
|
+
._y inv nat y_scaled
|
|
321
|
+
}
|
|
322
|
+
{
|
|
323
|
+
.x x,
|
|
324
|
+
._y _y,
|
|
325
|
+
.steps steps,
|
|
326
|
+
.q q,
|
|
327
|
+
.y_scaled y_scaled,
|
|
328
|
+
{.y_scaled x, .x y} inOrder test
|
|
329
|
+
}
|
|
330
|
+
<
|
|
331
|
+
// If x >= y_scaled, subtract and emit quotient bit 1
|
|
332
|
+
{
|
|
333
|
+
.test /yes if,
|
|
334
|
+
{
|
|
335
|
+
{.x int x, .y_scaled int y} minus /+ x,
|
|
336
|
+
.q |1 q,
|
|
337
|
+
._y _y,
|
|
338
|
+
.steps steps
|
|
339
|
+
} then
|
|
340
|
+
} .then,
|
|
341
|
+
// If x < y_scaled, keep x and emit quotient bit 0
|
|
342
|
+
{
|
|
343
|
+
.test /no if,
|
|
344
|
+
{.x x, .q |0 q, ._y _y, .steps steps} then
|
|
345
|
+
} .then
|
|
346
|
+
>
|
|
347
|
+
<
|
|
348
|
+
// If no more shift steps remaining, division is complete
|
|
349
|
+
{
|
|
350
|
+
.steps empty? if,
|
|
351
|
+
{.q inv int div, .x rem} then
|
|
352
|
+
} .then,
|
|
353
|
+
// Otherwise down-shift: remove the last 0 from _y and steps
|
|
354
|
+
{
|
|
355
|
+
.x x,
|
|
356
|
+
._y /0 _y,
|
|
357
|
+
.steps /0 steps,
|
|
358
|
+
.q q
|
|
359
|
+
} _div_down
|
|
360
|
+
>;
|
|
298
361
|
|
|
362
|
+
$ choose_div = < {} down_shift, {} restore >;
|
|
299
363
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
364
|
+
// Evaluates whether |x| < 2|y| by advancing 2 bits of x per 1 bit of y
|
|
365
|
+
_check_2y = ${bits x, bits y}
|
|
366
|
+
<
|
|
367
|
+
// x is empty -> |x| < 2|y| (choose down_shift)
|
|
368
|
+
{.x empty? if, {} | down_shift $choose_div then} .then,
|
|
369
|
+
// y is empty while x remains -> |x| >= 2|y| (choose restore)
|
|
370
|
+
{.y empty? if, {} | restore $choose_div then} .then,
|
|
371
|
+
// x has only 1 bit left while y remains -> |x| < 2|y|
|
|
372
|
+
{.x </0, /1> empty? if, {} | down_shift $choose_div then} .then,
|
|
373
|
+
// Advance 2 bits from x and 1 bit from y
|
|
374
|
+
{
|
|
375
|
+
.x </0, /1> </0, /1> x,
|
|
376
|
+
.y </0, /1> y
|
|
377
|
+
} _check_2y
|
|
378
|
+
>;
|
|
304
379
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
{._x |0 _x, .k dec k} _x_times_2_to_the_power_of_k
|
|
308
|
-
>
|
|
309
|
-
;
|
|
310
|
-
|
|
311
|
-
div =
|
|
312
|
-
${int x, int y}
|
|
313
|
-
// remember sign
|
|
380
|
+
// Public division interface
|
|
381
|
+
div = ${int x, int y}
|
|
314
382
|
{
|
|
315
383
|
<
|
|
316
384
|
{ .x/'+' if, .y get_sign then } .then,
|
|
317
|
-
{ .x/'-' if, .y
|
|
385
|
+
{ .x/'-' if, .y swap_sign get_sign then } .then
|
|
318
386
|
> sign,
|
|
319
|
-
|
|
387
|
+
.x abs remove_leading_zeros x_norm,
|
|
388
|
+
.y abs remove_leading_zeros y_norm
|
|
320
389
|
}
|
|
321
|
-
<
|
|
322
|
-
|
|
323
|
-
{
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
.
|
|
332
|
-
|
|
333
|
-
}
|
|
334
|
-
<
|
|
335
|
-
{ .log int zero_int? if, {.res div, .x rem} then } .then,
|
|
336
|
-
{
|
|
337
|
-
{1 x, .log int dec abs k} x_times_2_to_k factor,
|
|
338
|
-
() i
|
|
339
|
-
}
|
|
390
|
+
<
|
|
391
|
+
// Case 1: x == 0 -> quotient 0, remainder 0
|
|
392
|
+
{
|
|
393
|
+
.x_norm empty? if,
|
|
394
|
+
{ 0 int div, 0 rem } then
|
|
395
|
+
} .then,
|
|
396
|
+
// Case 2: |x| < |y| -> x < y, quotient 0, remainder x
|
|
397
|
+
{
|
|
398
|
+
{.y_norm x, .x_norm y} GT if,
|
|
399
|
+
{ 0 int div, .x_norm rem } then
|
|
400
|
+
} .then,
|
|
401
|
+
// Case 3: general division via adaptive hybrid choice
|
|
340
402
|
{
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
403
|
+
.sign sign,
|
|
404
|
+
{
|
|
405
|
+
.x_norm x,
|
|
406
|
+
.y_norm y,
|
|
407
|
+
{.x_norm x, .y_norm y} _check_2y choice
|
|
408
|
+
}
|
|
409
|
+
<
|
|
410
|
+
// If |x| < 2|y|, use down-shift division
|
|
411
|
+
{
|
|
412
|
+
.choice /down_shift if,
|
|
413
|
+
{
|
|
414
|
+
.x x,
|
|
415
|
+
{.x x, .y y, .y inv _y} _align_down aligned
|
|
416
|
+
}
|
|
417
|
+
{
|
|
418
|
+
.x x,
|
|
419
|
+
.aligned._y _y,
|
|
420
|
+
.aligned.steps steps,
|
|
421
|
+
0b q
|
|
422
|
+
} _div_down then
|
|
423
|
+
} .then,
|
|
424
|
+
// If |x| >= 2|y|, use restoring long division
|
|
425
|
+
{
|
|
426
|
+
.choice /restore if,
|
|
427
|
+
{.x x, .y y, 0 r, 0b q} _div_restoring then
|
|
428
|
+
} .then
|
|
429
|
+
> res
|
|
430
|
+
}
|
|
431
|
+
<
|
|
432
|
+
{.sign/'+' if, {.res.div div, .res.rem rem} then} .then,
|
|
433
|
+
{ .res.div swap_sign div, .res.rem rem }
|
|
434
|
+
>
|
|
345
435
|
>;
|
|
346
436
|
|
|
347
437
|
|
|
438
|
+
// ----------------------------------------------------------------------
|
|
439
|
+
// Number Theory: Modulo, Greatest Common Divisor, Least Common Multiple
|
|
440
|
+
// ----------------------------------------------------------------------
|
|
441
|
+
|
|
442
|
+
// Modulo: remainder of x divided by y in $bits, delegated to div
|
|
443
|
+
mod = ${bits x, bits y}
|
|
444
|
+
{{.x int x, .y int y} div .rem rem} .rem;
|
|
445
|
+
|
|
446
|
+
// Greatest common divisor (Euclidean algorithm)
|
|
447
|
+
gcd = ${bits x, bits y}
|
|
448
|
+
<
|
|
449
|
+
{.y x, .x y} GT,
|
|
450
|
+
()
|
|
451
|
+
> _gcd
|
|
452
|
+
;
|
|
453
|
+
|
|
454
|
+
_gcd = <
|
|
455
|
+
{ .y remove_leading_zeros empty? if, .x nat then } .then,
|
|
456
|
+
{ .y x, mod y } _gcd
|
|
457
|
+
>;
|
|
458
|
+
|
|
459
|
+
// Least common multiple: (x / gcd(x, y)) * y
|
|
348
460
|
lcm =
|
|
349
461
|
${bits x, bits y}
|
|
350
|
-
{{.x int x,
|
|
462
|
+
{{.x int x, gcd int y} div .div x, .y int y} times abs
|
|
351
463
|
;
|
|
352
464
|
|
|
353
465
|
factorial = {()n, 1 int acc} factorial_;
|
package/Examples/poly.k
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
-- Examples/poly.k: Polymorphic list functions in k
|
|
2
|
-
-- Uses
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
-- Uses arbitrary-precision integers from Examples/arithmetics.k.
|
|
3
|
+
|
|
4
|
+
-- List constructors and destructors
|
|
5
|
+
list? = ?< {} nil, {X car, Y cdr} cons > = Y;
|
|
6
|
+
nil = {} | nil list?;
|
|
7
|
+
singleton = {() car, nil cdr} | cons list?;
|
|
8
|
+
cons = {.car car, .cdr cdr} | cons list?;
|
|
9
|
+
nil? = list? / nil nil;
|
|
10
|
+
car = list? /cons .car;
|
|
11
|
+
cdr = list? /cons .cdr;
|
|
12
|
+
|
|
13
|
+
-- Decrement an integer and normalize (stripping leading zeros)
|
|
6
14
|
pred_int = dec /'+' nat | '+';
|
|
7
15
|
|
|
8
16
|
-- Concatenate two lists: {xs, ys} -> list
|
|
@@ -82,7 +90,8 @@ gt? =
|
|
|
82
90
|
>
|
|
83
91
|
;
|
|
84
92
|
|
|
85
|
-
-- Split list into two halves by alternating elements:
|
|
93
|
+
-- Split list into two halves by alternating elements:
|
|
94
|
+
-- xs -> {first, second}
|
|
86
95
|
split = {() xs, nil first, nil second} _split;
|
|
87
96
|
_split = <
|
|
88
97
|
{.xs /nil if, {.first first, .second second} then} .then,
|
package/browser/repl-browser.mjs
CHANGED
|
@@ -477,7 +477,7 @@ function showVfsFilePreview(filename) {
|
|
|
477
477
|
function loadPreviewedFile() {
|
|
478
478
|
if (!currentPreviewFile) return;
|
|
479
479
|
closeVfsModal();
|
|
480
|
-
if (currentPreviewFile.endsWith(".mjs") || currentPreviewFile.startsWith("codecs/")) {
|
|
480
|
+
if (currentPreviewFile.endsWith(".mjs") || currentPreviewFile.endsWith(".js") || currentPreviewFile.startsWith("codecs/")) {
|
|
481
481
|
executeCommand(`:codec load ${currentPreviewFile}`);
|
|
482
482
|
} else {
|
|
483
483
|
executeCommand(`:load ${currentPreviewFile}`);
|
|
@@ -498,32 +498,49 @@ function downloadPreviewedFile() {
|
|
|
498
498
|
URL.revokeObjectURL(url);
|
|
499
499
|
}
|
|
500
500
|
|
|
501
|
-
// File Upload Handler
|
|
501
|
+
// File Upload Handler (adds file to VFS without auto-loading)
|
|
502
502
|
function handleFileUpload(file) {
|
|
503
|
-
|
|
504
|
-
|
|
503
|
+
return new Promise((resolve, reject) => {
|
|
504
|
+
const reader = new FileReader();
|
|
505
|
+
const isBinary = file.name.endsWith(".klib") ||
|
|
506
|
+
file.name.endsWith(".ko") ||
|
|
507
|
+
file.name.endsWith(".wasm");
|
|
508
|
+
|
|
509
|
+
reader.onload = (e) => {
|
|
510
|
+
let data;
|
|
511
|
+
if (isBinary) {
|
|
512
|
+
data = new Uint8Array(e.target.result);
|
|
513
|
+
} else {
|
|
514
|
+
data = e.target.result;
|
|
515
|
+
}
|
|
516
|
+
setVfsFile(file.name, data);
|
|
517
|
+
appendSystemMessage(
|
|
518
|
+
`📁 Uploaded <b>${escapeHtml(file.name)}</b> into VFS (` +
|
|
519
|
+
`${(data.length / 1024).toFixed(1)} KB).`,
|
|
520
|
+
false,
|
|
521
|
+
true
|
|
522
|
+
);
|
|
523
|
+
if (vfsModal && vfsModal.classList.contains("open")) {
|
|
524
|
+
renderVfsFileList();
|
|
525
|
+
showVfsFilePreview(file.name);
|
|
526
|
+
}
|
|
527
|
+
resolve();
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
reader.onerror = () => {
|
|
531
|
+
appendSystemMessage(
|
|
532
|
+
`❌ Error reading file: ${file.name}`,
|
|
533
|
+
true
|
|
534
|
+
);
|
|
535
|
+
reject(reader.error || new Error("Failed to read file"));
|
|
536
|
+
};
|
|
505
537
|
|
|
506
|
-
reader.onload = (e) => {
|
|
507
|
-
let data;
|
|
508
538
|
if (isBinary) {
|
|
509
|
-
|
|
539
|
+
reader.readAsArrayBuffer(file);
|
|
510
540
|
} else {
|
|
511
|
-
|
|
541
|
+
reader.readAsText(file);
|
|
512
542
|
}
|
|
513
|
-
|
|
514
|
-
appendSystemMessage(`📁 Uploaded <b>${escapeHtml(file.name)}</b> into VFS (${(data.length / 1024).toFixed(1)} KB).`);
|
|
515
|
-
if (file.name.endsWith("-codec.mjs") || file.name.endsWith("-codec.js") || file.name.includes("codec")) {
|
|
516
|
-
executeCommand(`:codec load ${file.name}`);
|
|
517
|
-
} else {
|
|
518
|
-
executeCommand(`:load ${file.name}`);
|
|
519
|
-
}
|
|
520
|
-
};
|
|
521
|
-
|
|
522
|
-
if (isBinary) {
|
|
523
|
-
reader.readAsArrayBuffer(file);
|
|
524
|
-
} else {
|
|
525
|
-
reader.readAsText(file);
|
|
526
|
-
}
|
|
543
|
+
});
|
|
527
544
|
}
|
|
528
545
|
|
|
529
546
|
// Export State as .klib
|
|
@@ -993,6 +1010,7 @@ if (typeof window !== "undefined") {
|
|
|
993
1010
|
getVfsFile,
|
|
994
1011
|
setVfsFile,
|
|
995
1012
|
getAllVfsFiles,
|
|
1013
|
+
handleFileUpload,
|
|
996
1014
|
openCodecsModal,
|
|
997
1015
|
registerCodec,
|
|
998
1016
|
unregisterCodec
|