@calcit/procs 0.5.0-a9 → 0.5.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.
@@ -1,9 +1,9 @@
1
1
  import "./js-primes";
2
2
  import { CalcitRef, CalcitSymbol, CalcitKeyword } from "./calcit-data";
3
- import { toPairs } from "@calcit/ternary-tree";
3
+ import "@calcit/ternary-tree";
4
4
  import { CalcitRecord } from "./js-record";
5
- import { CalcitMap } from "./js-map";
6
- import { CalcitList } from "./js-list";
5
+ import { CalcitMap, CalcitSliceMap } from "./js-map";
6
+ import { CalcitList, CalcitSliceList } from "./js-list";
7
7
  import { CalcitSet } from "./js-set";
8
8
  import { CalcitTuple } from "./js-tuple";
9
9
  let embedObject = (x) => {
@@ -28,7 +28,7 @@ export let load_console_formatter_$x_ = () => {
28
28
  if (obj instanceof CalcitSymbol) {
29
29
  return ["div", { style: "color: hsl(340, 80%, 60%)" }, obj.toString()];
30
30
  }
31
- if (obj instanceof CalcitList) {
31
+ if (obj instanceof CalcitList || obj instanceof CalcitSliceList) {
32
32
  return [
33
33
  "div",
34
34
  { style: "color: hsl(280, 80%, 60%, 0.4)" },
@@ -36,7 +36,7 @@ export let load_console_formatter_$x_ = () => {
36
36
  ["span", { style: "font-size: 80%; vertical-align: 0.7em; color: hsl(280, 80%, 60%, 0.8)" }, `${obj.len()}`],
37
37
  ];
38
38
  }
39
- if (obj instanceof CalcitMap) {
39
+ if (obj instanceof CalcitMap || obj instanceof CalcitSliceMap) {
40
40
  return ["div", { style: "color: hsl(280, 80%, 60%, 0.4)" }, obj.toString(true)];
41
41
  }
42
42
  if (obj instanceof CalcitSet) {
@@ -65,10 +65,10 @@ export let load_console_formatter_$x_ = () => {
65
65
  return null;
66
66
  },
67
67
  hasBody: (obj) => {
68
- if (obj instanceof CalcitList) {
68
+ if (obj instanceof CalcitList || obj instanceof CalcitSliceList) {
69
69
  return obj.len() > 0;
70
70
  }
71
- if (obj instanceof CalcitMap) {
71
+ if (obj instanceof CalcitMap || obj instanceof CalcitSliceMap) {
72
72
  return obj.len() > 0;
73
73
  }
74
74
  if (obj instanceof CalcitSet) {
@@ -77,7 +77,7 @@ export let load_console_formatter_$x_ = () => {
77
77
  return false;
78
78
  },
79
79
  body: (obj, config) => {
80
- if (obj instanceof CalcitList) {
80
+ if (obj instanceof CalcitList || obj instanceof CalcitSliceList) {
81
81
  return ["div", { style: "color: hsl(280, 80%, 60%)" }].concat(obj.toArray().map((x, idx) => {
82
82
  return [
83
83
  "div",
@@ -102,10 +102,10 @@ export let load_console_formatter_$x_ = () => {
102
102
  ret.push(["div", { style: "margin-left: 8px; display: inline-block;" }, embedObject(obj.snd)]);
103
103
  return ret;
104
104
  }
105
- if (obj instanceof CalcitMap) {
105
+ if (obj instanceof CalcitMap || obj instanceof CalcitSliceMap) {
106
106
  let ret = ["div", { style: "color: hsl(280, 80%, 60%)" }];
107
- obj.turnMap();
108
- for (let [k, v] of toPairs(obj.value)) {
107
+ let pairs = obj.pairs();
108
+ for (let [k, v] of pairs) {
109
109
  ret.push([
110
110
  "div",
111
111
  { style: "margin-left: 8px; display: flex;" },
package/lib/js-cirru.js CHANGED
@@ -1,9 +1,9 @@
1
- import { initTernaryTreeMap } from "@calcit/ternary-tree";
1
+ import "@calcit/ternary-tree";
2
2
  import { writeCirruCode } from "@cirru/writer.ts";
3
3
  import "./js-primes";
4
- import { CalcitList } from "./js-list";
4
+ import { CalcitList, CalcitSliceList } from "./js-list";
5
5
  import { CalcitRecord } from "./js-record";
6
- import { CalcitMap } from "./js-map";
6
+ import { CalcitMap, CalcitSliceMap } from "./js-map";
7
7
  import { CalcitSet } from "./js-set";
8
8
  import { CalcitKeyword, CalcitSymbol, CalcitRecur, CalcitRef, kwd } from "./calcit-data";
9
9
  import { CalcitTuple } from "./js-tuple";
@@ -39,11 +39,11 @@ export let to_cirru_edn = (x) => {
39
39
  if (x instanceof CalcitSymbol) {
40
40
  return x.toString();
41
41
  }
42
- if (x instanceof CalcitList) {
42
+ if (x instanceof CalcitList || x instanceof CalcitSliceList) {
43
43
  // TODO can be faster
44
44
  return ["[]"].concat(x.toArray().map(to_cirru_edn));
45
45
  }
46
- if (x instanceof CalcitMap) {
46
+ if (x instanceof CalcitMap || x instanceof CalcitSliceMap) {
47
47
  let buffer = ["{}"];
48
48
  for (let [k, v] of x.pairs()) {
49
49
  buffer.push([to_cirru_edn(k), to_cirru_edn(v)]);
@@ -101,7 +101,7 @@ export let extract_cirru_edn = (x) => {
101
101
  if (x === "false") {
102
102
  return false;
103
103
  }
104
- if (x == "") {
104
+ if (x === "") {
105
105
  throw new Error("cannot be empty");
106
106
  }
107
107
  if (x[0] === "|" || x[0] === '"') {
@@ -127,17 +127,17 @@ export let extract_cirru_edn = (x) => {
127
127
  if (x[0] === "{}") {
128
128
  let result = [];
129
129
  x.forEach((pair, idx) => {
130
- if (idx == 0) {
130
+ if (idx === 0) {
131
131
  return; // skip first `{}` symbol
132
132
  }
133
- if (pair instanceof Array && pair.length == 2) {
134
- result.push([extract_cirru_edn(pair[0]), extract_cirru_edn(pair[1])]);
133
+ if (pair instanceof Array && pair.length === 2) {
134
+ result.push(extract_cirru_edn(pair[0]), extract_cirru_edn(pair[1]));
135
135
  }
136
136
  else {
137
137
  throw new Error("Expected pairs for map");
138
138
  }
139
139
  });
140
- return new CalcitMap(initTernaryTreeMap(result));
140
+ return new CalcitSliceMap(result);
141
141
  }
142
142
  if (x[0] === "%{}") {
143
143
  let name = x[1];
@@ -150,7 +150,7 @@ export let extract_cirru_edn = (x) => {
150
150
  if (idx <= 1) {
151
151
  return; // skip %{} name
152
152
  }
153
- if (pair instanceof Array && pair.length == 2) {
153
+ if (pair instanceof Array && pair.length === 2) {
154
154
  if (typeof pair[0] === "string") {
155
155
  entries.push([extractFieldKwd(pair[0]), extract_cirru_edn(pair[1])]);
156
156
  }
@@ -174,7 +174,7 @@ export let extract_cirru_edn = (x) => {
174
174
  return new CalcitRecord(extractFieldKwd(name), fields, values);
175
175
  }
176
176
  if (x[0] === "[]") {
177
- return new CalcitList(x.slice(1).map(extract_cirru_edn));
177
+ return new CalcitSliceList(x.slice(1).map(extract_cirru_edn));
178
178
  }
179
179
  if (x[0] === "#{}") {
180
180
  return new CalcitSet(x.slice(1).map(extract_cirru_edn));
@@ -205,10 +205,10 @@ export let format_cirru_edn = (data, useInline = true) => {
205
205
  if (typeof data === "string") {
206
206
  return "\ndo " + to_cirru_edn(data) + "\n";
207
207
  }
208
- if (typeof data == "boolean") {
208
+ if (typeof data === "boolean") {
209
209
  return "\ndo " + to_cirru_edn(data) + "\n";
210
210
  }
211
- if (typeof data == "string") {
211
+ if (typeof data === "string") {
212
212
  return "\ndo " + to_cirru_edn(data) + "\n";
213
213
  }
214
214
  if (data instanceof CalcitSymbol) {
@@ -239,7 +239,7 @@ export let to_calcit_data = (x, noKeyword = false) => {
239
239
  x.forEach((v) => {
240
240
  result.push(to_calcit_data(v, noKeyword));
241
241
  });
242
- return new CalcitList(result);
242
+ return new CalcitSliceList(result);
243
243
  }
244
244
  if (x instanceof Set) {
245
245
  let result = [];
@@ -248,9 +248,9 @@ export let to_calcit_data = (x, noKeyword = false) => {
248
248
  });
249
249
  return new CalcitSet(result);
250
250
  }
251
- if (x instanceof CalcitList)
251
+ if (x instanceof CalcitList || x instanceof CalcitSliceList)
252
252
  return x;
253
- if (x instanceof CalcitMap)
253
+ if (x instanceof CalcitMap || x instanceof CalcitSliceMap)
254
254
  return x;
255
255
  if (x instanceof CalcitSet)
256
256
  return x;
@@ -270,9 +270,9 @@ export let to_calcit_data = (x, noKeyword = false) => {
270
270
  if (x === Object(x)) {
271
271
  let result = [];
272
272
  Object.keys(x).forEach((k) => {
273
- result.push([to_calcit_data(k, noKeyword), to_calcit_data(x[k], noKeyword)]);
273
+ result.push(to_calcit_data(k, noKeyword), to_calcit_data(x[k], noKeyword));
274
274
  });
275
- return new CalcitMap(initTernaryTreeMap(result));
275
+ return new CalcitSliceMap(result);
276
276
  }
277
277
  console.error(x);
278
278
  throw new Error("Unexpected data for converting");
@@ -281,7 +281,7 @@ let toWriterNode = (xs) => {
281
281
  if (typeof xs === "string") {
282
282
  return xs;
283
283
  }
284
- if (xs instanceof CalcitList) {
284
+ if (xs instanceof CalcitList || xs instanceof CalcitSliceList) {
285
285
  return xs.toArray().map(toWriterNode);
286
286
  }
287
287
  else {
package/lib/js-list.js CHANGED
@@ -1,92 +1,153 @@
1
1
  import * as ternaryTree from "@calcit/ternary-tree";
2
2
  import "./js-primes";
3
- import { initTernaryTreeList, listLen, listGet, assocList, listToItems, dissocList, assocBefore, assocAfter, } from "@calcit/ternary-tree";
4
- import { CalcitMap } from "./js-map";
3
+ import { initTernaryTreeList, initTernaryTreeListFromRange, listLen, listGet, assocList, listToItems, dissocList, assocBefore, assocAfter, } from "@calcit/ternary-tree";
4
+ import { CalcitMap, CalcitSliceMap } from "./js-map";
5
5
  import { CalcitSet } from "./js-set";
6
6
  import { CalcitTuple } from "./js-tuple";
7
- import "./calcit.procs";
8
7
  import { isNestedCalcitData, tipNestedCalcitData, toString } from "./calcit-data";
8
+ // two list implementations, should offer same interface
9
9
  export class CalcitList {
10
10
  constructor(value) {
11
- if (value == null) {
12
- value = []; // dirty, better handled from outside
13
- }
14
11
  this.cachedHash = null;
15
- if (Array.isArray(value)) {
16
- this.arrayMode = true;
17
- this.arrayValue = value;
18
- this.arrayStart = 0;
19
- this.arrayEnd = value.length;
20
- this.value = null;
12
+ if (value == null) {
13
+ this.value = initTernaryTreeList([]);
21
14
  }
22
15
  else {
23
- this.arrayMode = false;
24
16
  this.value = value;
25
- this.arrayValue = [];
26
- this.arrayStart = null;
27
- this.arrayEnd = null;
28
- }
29
- }
30
- turnListMode() {
31
- if (this.arrayMode) {
32
- this.value = initTernaryTreeList(this.arrayValue.slice(this.arrayStart, this.arrayEnd));
33
- this.arrayValue = null;
34
- this.arrayStart = null;
35
- this.arrayEnd = null;
36
- this.arrayMode = false;
37
17
  }
38
18
  }
39
19
  len() {
40
- if (this.arrayMode) {
41
- return this.arrayEnd - this.arrayStart;
42
- }
43
- else {
44
- return listLen(this.value);
45
- }
20
+ return listLen(this.value);
46
21
  }
47
22
  get(idx) {
48
- if (this.arrayMode) {
49
- return this.arrayValue[this.arrayStart + idx];
50
- }
51
- else {
52
- return listGet(this.value, idx);
53
- }
23
+ return listGet(this.value, idx);
54
24
  }
55
25
  assoc(idx, v) {
56
- this.turnListMode();
57
26
  return new CalcitList(assocList(this.value, idx, v));
58
27
  }
59
28
  assocBefore(idx, v) {
60
- this.turnListMode();
61
29
  return new CalcitList(assocBefore(this.value, idx, v));
62
30
  }
63
31
  assocAfter(idx, v) {
64
- this.turnListMode();
65
32
  return new CalcitList(assocAfter(this.value, idx, v));
66
33
  }
67
34
  dissoc(idx) {
68
- this.turnListMode();
69
35
  return new CalcitList(dissocList(this.value, idx));
70
36
  }
71
37
  slice(from, to) {
72
- if (this.arrayMode) {
73
- if (from < 0) {
74
- throw new Error(`from index too small: ${from}`);
75
- }
76
- if (to > this.len()) {
77
- throw new Error(`end index too large: ${to}`);
38
+ return new CalcitList(ternaryTree.slice(this.value, from, to));
39
+ }
40
+ toString(shorter = false) {
41
+ let result = "";
42
+ for (let item of this.items()) {
43
+ if (shorter && isNestedCalcitData(item)) {
44
+ result = `${result} ${tipNestedCalcitData(item)}`;
78
45
  }
79
- if (to < from) {
80
- throw new Error("end index too small");
46
+ else {
47
+ result = `${result} ${toString(item, true)}`;
81
48
  }
82
- let result = new CalcitList(this.arrayValue);
83
- result.arrayStart = this.arrayStart + from;
84
- result.arrayEnd = this.arrayStart + to;
85
- return result;
49
+ }
50
+ return `([]${result})`;
51
+ }
52
+ isEmpty() {
53
+ return this.len() === 0;
54
+ }
55
+ /** usage: `for of` */
56
+ items() {
57
+ return listToItems(this.value);
58
+ }
59
+ append(v) {
60
+ return new CalcitList(ternaryTree.append(this.value, v));
61
+ }
62
+ prepend(v) {
63
+ return new CalcitList(ternaryTree.prepend(this.value, v));
64
+ }
65
+ first() {
66
+ return ternaryTree.first(this.value);
67
+ }
68
+ rest() {
69
+ return new CalcitList(ternaryTree.rest(this.value));
70
+ }
71
+ concat(ys) {
72
+ if (ys instanceof CalcitSliceList) {
73
+ return new CalcitList(ternaryTree.concat(this.value, ys.turnListMode().value));
74
+ }
75
+ else if (ys instanceof CalcitList) {
76
+ return new CalcitList(ternaryTree.concat(this.value, ys.value));
86
77
  }
87
78
  else {
88
- return new CalcitList(ternaryTree.slice(this.value, from, to));
79
+ throw new Error(`Unknown data to concat: ${ys}`);
80
+ }
81
+ }
82
+ map(f) {
83
+ return new CalcitList(ternaryTree.listMapValues(this.value, f));
84
+ }
85
+ toArray() {
86
+ return [...ternaryTree.listToItems(this.value)];
87
+ }
88
+ reverse() {
89
+ return new CalcitList(ternaryTree.reverse(this.value));
90
+ }
91
+ }
92
+ // represent append-only immutable list in Array slices
93
+ export class CalcitSliceList {
94
+ constructor(value) {
95
+ if (value == null) {
96
+ value = []; // dirty, better handled from outside
89
97
  }
98
+ this.cachedHash = null;
99
+ this.value = value;
100
+ this.start = 0;
101
+ this.end = value.length;
102
+ }
103
+ turnListMode() {
104
+ return new CalcitList(initTernaryTreeListFromRange(this.value, this.start, this.end));
105
+ }
106
+ len() {
107
+ return this.end - this.start;
108
+ }
109
+ get(idx) {
110
+ return this.value[this.start + idx];
111
+ }
112
+ assoc(idx, v) {
113
+ return this.turnListMode().assoc(idx, v);
114
+ }
115
+ assocBefore(idx, v) {
116
+ return this.turnListMode().assocBefore(idx, v);
117
+ }
118
+ assocAfter(idx, v) {
119
+ if (idx === this.len() - 1) {
120
+ return this.append(v);
121
+ }
122
+ else {
123
+ return this.turnListMode().assocAfter(idx, v);
124
+ }
125
+ }
126
+ dissoc(idx) {
127
+ if (idx === 0) {
128
+ return this.rest();
129
+ }
130
+ else if (idx === this.len() - 1) {
131
+ return this.slice(0, idx);
132
+ }
133
+ else {
134
+ return this.turnListMode().dissoc(idx);
135
+ }
136
+ }
137
+ slice(from, to) {
138
+ if (from < 0) {
139
+ throw new Error(`from index too small: ${from}`);
140
+ }
141
+ if (to > this.len()) {
142
+ throw new Error(`end index too large: ${to}`);
143
+ }
144
+ if (to < from) {
145
+ throw new Error("end index too small");
146
+ }
147
+ let result = new CalcitSliceList(this.value);
148
+ result.start = this.start + from;
149
+ result.end = this.start + to;
150
+ return result;
90
151
  }
91
152
  toString(shorter = false) {
92
153
  let result = "";
@@ -105,59 +166,40 @@ export class CalcitList {
105
166
  }
106
167
  /** usage: `for of` */
107
168
  items() {
108
- if (this.arrayMode) {
109
- return sliceGenerator(this.arrayValue, this.arrayStart, this.arrayEnd);
110
- }
111
- else {
112
- return listToItems(this.value);
113
- }
169
+ return sliceGenerator(this.value, this.start, this.end);
114
170
  }
115
171
  append(v) {
116
- if (this.arrayMode && this.arrayEnd === this.arrayValue.length && this.arrayStart < 32) {
172
+ if (this.end === this.value.length && this.start < 32) {
117
173
  // dirty trick to reuse list memory, data storage actually appended at existing array
118
- this.arrayValue.push(v);
119
- let newList = new CalcitList(this.arrayValue);
120
- newList.arrayStart = this.arrayStart;
121
- newList.arrayEnd = this.arrayEnd + 1;
174
+ this.value.push(v);
175
+ let newList = new CalcitSliceList(this.value);
176
+ newList.start = this.start;
177
+ newList.end = this.end + 1;
122
178
  return newList;
123
179
  }
124
180
  else {
125
- this.turnListMode();
126
- return new CalcitList(ternaryTree.append(this.value, v));
181
+ return this.turnListMode().append(v);
127
182
  }
128
183
  }
129
184
  prepend(v) {
130
- this.turnListMode();
131
- return new CalcitList(ternaryTree.prepend(this.value, v));
185
+ return this.turnListMode().prepend(v);
132
186
  }
133
187
  first() {
134
- if (this.arrayMode) {
135
- if (this.arrayValue.length > this.arrayStart) {
136
- return this.arrayValue[this.arrayStart];
137
- }
138
- else {
139
- return null;
140
- }
188
+ if (this.value.length > this.start) {
189
+ return this.value[this.start];
141
190
  }
142
191
  else {
143
- return ternaryTree.first(this.value);
192
+ return null;
144
193
  }
145
194
  }
146
195
  rest() {
147
- if (this.arrayMode) {
148
- return this.slice(1, this.arrayEnd - this.arrayStart);
149
- }
150
- else {
151
- return new CalcitList(ternaryTree.rest(this.value));
152
- }
196
+ return this.slice(1, this.end - this.start);
153
197
  }
198
+ // TODO
154
199
  concat(ys) {
155
- if (!(ys instanceof CalcitList)) {
156
- throw new Error("Expected list");
157
- }
158
- if (this.arrayMode && ys.arrayMode) {
159
- let size = this.arrayEnd - this.arrayStart;
160
- let otherSize = ys.arrayEnd - ys.arrayStart;
200
+ if (ys instanceof CalcitSliceList) {
201
+ let size = this.end - this.start;
202
+ let otherSize = ys.end - ys.start;
161
203
  let combined = new Array(size + otherSize);
162
204
  for (let i = 0; i < size; i++) {
163
205
  combined[i] = this.get(i);
@@ -165,38 +207,39 @@ export class CalcitList {
165
207
  for (let i = 0; i < otherSize; i++) {
166
208
  combined[i + size] = ys.get(i);
167
209
  }
168
- return new CalcitList(combined);
210
+ return new CalcitSliceList(combined);
211
+ }
212
+ else if (ys instanceof CalcitList) {
213
+ return this.turnListMode().concat(ys);
169
214
  }
170
215
  else {
171
- this.turnListMode();
172
- ys.turnListMode();
173
- return new CalcitList(ternaryTree.concat(this.value, ys.value));
216
+ throw new Error("Expected list");
174
217
  }
175
218
  }
176
219
  map(f) {
177
- if (this.arrayMode) {
178
- return new CalcitList(this.arrayValue.slice(this.arrayStart, this.arrayEnd).map(f));
179
- }
180
- else {
181
- return new CalcitList(ternaryTree.listMapValues(this.value, f));
220
+ let ys = [];
221
+ for (let x in sliceGenerator(this.value, this.start, this.end)) {
222
+ ys.push(f(x));
182
223
  }
224
+ return new CalcitSliceList(ys);
183
225
  }
184
226
  toArray() {
185
- if (this.arrayMode) {
186
- return this.arrayValue.slice(this.arrayStart, this.arrayEnd);
187
- }
188
- else {
189
- return [...ternaryTree.listToItems(this.value)];
190
- }
227
+ return this.value.slice(this.start, this.end);
191
228
  }
192
229
  reverse() {
193
- this.turnListMode();
194
- return new CalcitList(ternaryTree.reverse(this.value));
230
+ return this.turnListMode().reverse();
195
231
  }
196
232
  }
197
233
  function* sliceGenerator(xs, start, end) {
198
- for (let idx = start; idx < end; idx++) {
199
- yield xs[idx];
234
+ if (xs == null) {
235
+ if (end <= start) {
236
+ throw new Error("invalid list to slice");
237
+ }
238
+ }
239
+ else {
240
+ for (let idx = start; idx < end; idx++) {
241
+ yield xs[idx];
242
+ }
200
243
  }
201
244
  }
202
245
  export let foldl = function (xs, acc, f) {
@@ -204,10 +247,9 @@ export let foldl = function (xs, acc, f) {
204
247
  throw new Error("foldl takes 3 arguments");
205
248
  }
206
249
  if (f == null) {
207
- debugger;
208
250
  throw new Error("Expected function for folding");
209
251
  }
210
- if (xs instanceof CalcitList) {
252
+ if (xs instanceof CalcitSliceList || xs instanceof CalcitList) {
211
253
  var result = acc;
212
254
  for (let idx = 0; idx < xs.len(); idx++) {
213
255
  let item = xs.get(idx);
@@ -222,10 +264,20 @@ export let foldl = function (xs, acc, f) {
222
264
  });
223
265
  return result;
224
266
  }
267
+ if (xs instanceof CalcitSliceMap) {
268
+ let result = acc;
269
+ // low-level code for performance
270
+ let size = xs.chunk.length >> 1;
271
+ for (let i = 0; i < size; i++) {
272
+ let pos = i << 1;
273
+ result = f(result, new CalcitSliceList([xs.chunk[pos], xs.chunk[pos + 1]]));
274
+ }
275
+ return result;
276
+ }
225
277
  if (xs instanceof CalcitMap) {
226
278
  let result = acc;
227
- xs.pairs().forEach(([k, item]) => {
228
- result = f(result, new CalcitList([k, item]));
279
+ xs.pairs().forEach((pair) => {
280
+ result = f(result, new CalcitSliceList(pair));
229
281
  });
230
282
  return result;
231
283
  }
@@ -236,10 +288,9 @@ export let foldl_shortcut = function (xs, acc, v0, f) {
236
288
  throw new Error("foldl-shortcut takes 4 arguments");
237
289
  }
238
290
  if (f == null) {
239
- debugger;
240
291
  throw new Error("Expected function for folding");
241
292
  }
242
- if (xs instanceof CalcitList) {
293
+ if (xs instanceof CalcitList || xs instanceof CalcitSliceList) {
243
294
  var state = acc;
244
295
  for (let idx = 0; idx < xs.len(); idx++) {
245
296
  let item = xs.get(idx);
@@ -280,10 +331,33 @@ export let foldl_shortcut = function (xs, acc, v0, f) {
280
331
  }
281
332
  return v0;
282
333
  }
334
+ if (xs instanceof CalcitSliceMap) {
335
+ let state = acc;
336
+ // low-level code for performance
337
+ let size = xs.chunk.length >> 1;
338
+ for (let i = 0; i < size; i++) {
339
+ let pos = i << 1;
340
+ let pair = f(state, new CalcitSliceList([xs.chunk[pos], xs.chunk[pos + 1]]));
341
+ if (pair instanceof CalcitTuple) {
342
+ if (typeof pair.fst === "boolean") {
343
+ if (pair.fst) {
344
+ return pair.snd;
345
+ }
346
+ else {
347
+ state = pair.snd;
348
+ }
349
+ }
350
+ }
351
+ else {
352
+ throw new Error("Expected return value in `:: bool acc` structure");
353
+ }
354
+ }
355
+ return v0;
356
+ }
283
357
  if (xs instanceof CalcitMap) {
284
358
  let state = acc;
285
359
  for (let item of xs.pairs()) {
286
- let pair = f(state, new CalcitList(item));
360
+ let pair = f(state, new CalcitSliceList(item));
287
361
  if (pair instanceof CalcitTuple) {
288
362
  if (typeof pair.fst === "boolean") {
289
363
  if (pair.fst) {
@@ -307,10 +381,9 @@ export let foldr_shortcut = function (xs, acc, v0, f) {
307
381
  throw new Error("foldr-shortcut takes 4 arguments");
308
382
  }
309
383
  if (f == null) {
310
- debugger;
311
384
  throw new Error("Expected function for folding");
312
385
  }
313
- if (xs instanceof CalcitList) {
386
+ if (xs instanceof CalcitList || xs instanceof CalcitSliceList) {
314
387
  var state = acc;
315
388
  // iterate from right
316
389
  for (let idx = xs.len() - 1; idx >= 0; idx--) {