@mojir/lits 2.2.4 → 2.3.1

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.
Files changed (74) hide show
  1. package/README.md +2 -1
  2. package/dist/cli/cli.js +1471 -1126
  3. package/dist/cli/reference/api.d.ts +5 -5
  4. package/dist/cli/reference/index.d.ts +8 -2
  5. package/dist/cli/src/Lits/Lits.d.ts +8 -2
  6. package/dist/cli/src/builtin/bindingNode.d.ts +2 -1
  7. package/dist/cli/src/builtin/interface.d.ts +3 -2
  8. package/dist/cli/src/builtin/modules/number-theory/sequences/index.d.ts +2 -1
  9. package/dist/cli/src/evaluator/functionExecutors.d.ts +2 -1
  10. package/dist/cli/src/evaluator/index.d.ts +3 -2
  11. package/dist/cli/src/evaluator/interface.d.ts +3 -2
  12. package/dist/cli/src/tokenizer/operators.d.ts +2 -2
  13. package/dist/cli/src/utils/maybePromise.d.ts +54 -0
  14. package/dist/full.esm.js +1 -1
  15. package/dist/full.esm.js.map +1 -1
  16. package/dist/full.js +1 -1
  17. package/dist/full.js.map +1 -1
  18. package/dist/index.esm.js +1 -1
  19. package/dist/index.esm.js.map +1 -1
  20. package/dist/index.js +1 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/lits.iife.js +1 -1
  23. package/dist/lits.iife.js.map +1 -1
  24. package/dist/modules/assert.esm.js +1 -1
  25. package/dist/modules/assert.esm.js.map +1 -1
  26. package/dist/modules/assert.js +1 -1
  27. package/dist/modules/assert.js.map +1 -1
  28. package/dist/modules/collection.esm.js +1 -1
  29. package/dist/modules/collection.esm.js.map +1 -1
  30. package/dist/modules/collection.js +1 -1
  31. package/dist/modules/collection.js.map +1 -1
  32. package/dist/modules/grid.esm.js +1 -1
  33. package/dist/modules/grid.esm.js.map +1 -1
  34. package/dist/modules/grid.js +1 -1
  35. package/dist/modules/grid.js.map +1 -1
  36. package/dist/modules/number-theory.esm.js +1 -1
  37. package/dist/modules/number-theory.esm.js.map +1 -1
  38. package/dist/modules/number-theory.js +1 -1
  39. package/dist/modules/number-theory.js.map +1 -1
  40. package/dist/modules/reference/api.d.ts +5 -5
  41. package/dist/modules/reference/index.d.ts +8 -2
  42. package/dist/modules/sequence.esm.js +1 -1
  43. package/dist/modules/sequence.esm.js.map +1 -1
  44. package/dist/modules/sequence.js +1 -1
  45. package/dist/modules/sequence.js.map +1 -1
  46. package/dist/modules/src/Lits/Lits.d.ts +8 -2
  47. package/dist/modules/src/builtin/bindingNode.d.ts +2 -1
  48. package/dist/modules/src/builtin/interface.d.ts +3 -2
  49. package/dist/modules/src/builtin/modules/number-theory/sequences/index.d.ts +2 -1
  50. package/dist/modules/src/evaluator/functionExecutors.d.ts +2 -1
  51. package/dist/modules/src/evaluator/index.d.ts +3 -2
  52. package/dist/modules/src/evaluator/interface.d.ts +3 -2
  53. package/dist/modules/src/tokenizer/operators.d.ts +2 -2
  54. package/dist/modules/src/utils/maybePromise.d.ts +54 -0
  55. package/dist/modules/vector.esm.js +1 -1
  56. package/dist/modules/vector.esm.js.map +1 -1
  57. package/dist/modules/vector.js +1 -1
  58. package/dist/modules/vector.js.map +1 -1
  59. package/dist/reference/api.d.ts +5 -5
  60. package/dist/reference/index.d.ts +8 -2
  61. package/dist/src/Lits/Lits.d.ts +8 -2
  62. package/dist/src/builtin/bindingNode.d.ts +2 -1
  63. package/dist/src/builtin/interface.d.ts +3 -2
  64. package/dist/src/builtin/modules/number-theory/sequences/index.d.ts +2 -1
  65. package/dist/src/evaluator/functionExecutors.d.ts +2 -1
  66. package/dist/src/evaluator/index.d.ts +3 -2
  67. package/dist/src/evaluator/interface.d.ts +3 -2
  68. package/dist/src/tokenizer/operators.d.ts +2 -2
  69. package/dist/src/utils/maybePromise.d.ts +54 -0
  70. package/dist/testFramework.esm.js +1 -1
  71. package/dist/testFramework.esm.js.map +1 -1
  72. package/dist/testFramework.js +1 -1
  73. package/dist/testFramework.js.map +1 -1
  74. package/package.json +1 -1
package/dist/cli/cli.js CHANGED
@@ -7,7 +7,7 @@ var readline = require('node:readline');
7
7
  var os = require('node:os');
8
8
  var process$1 = require('node:process');
9
9
 
10
- var version = "2.2.4";
10
+ var version = "2.3.1";
11
11
 
12
12
  function getCodeMarker(sourceCodeInfo) {
13
13
  if (!sourceCodeInfo.position || !sourceCodeInfo.code)
@@ -858,6 +858,200 @@ function assertCharArray(value, sourceCodeInfo) {
858
858
  throw getAssertionError('array of strings', value, sourceCodeInfo);
859
859
  }
860
860
 
861
+ /**
862
+ * MaybePromise utilities for transparent async support.
863
+ *
864
+ * The sync path stays zero-overhead — when no async JS functions are involved,
865
+ * everything runs synchronously with only `instanceof Promise` checks as overhead.
866
+ * When an async value is detected, the evaluation chain switches to Promise-based
867
+ * execution for the remainder.
868
+ */
869
+ /**
870
+ * Chain a value that might be a Promise. If the value is sync, calls fn synchronously.
871
+ * If it's a Promise, chains with .then().
872
+ */
873
+ function chain(value, fn) {
874
+ if (value instanceof Promise) {
875
+ return value.then(fn);
876
+ }
877
+ return fn(value);
878
+ }
879
+ /**
880
+ * Like Array.map but handles MaybePromise callbacks sequentially.
881
+ * In the sync case, runs as a simple loop. Switches to async only when needed.
882
+ */
883
+ function mapSequential(arr, fn) {
884
+ const results = [];
885
+ for (let i = 0; i < arr.length; i++) {
886
+ const result = fn(arr[i], i);
887
+ if (result instanceof Promise) {
888
+ return chainRemainingMap(result, results, arr, fn, i);
889
+ }
890
+ results.push(result);
891
+ }
892
+ return results;
893
+ }
894
+ async function chainRemainingMap(currentPromise, results, arr, fn, startIndex) {
895
+ results.push(await currentPromise);
896
+ for (let i = startIndex + 1; i < arr.length; i++) {
897
+ results.push(await fn(arr[i], i));
898
+ }
899
+ return results;
900
+ }
901
+ /**
902
+ * Like Array.reduce but handles MaybePromise callbacks sequentially.
903
+ * In the sync case, runs as a simple loop. Switches to async only when needed.
904
+ */
905
+ function reduceSequential(arr, fn, initial) {
906
+ let result = initial;
907
+ for (let i = 0; i < arr.length; i++) {
908
+ const next = fn(result, arr[i], i);
909
+ if (next instanceof Promise) {
910
+ return chainRemainingReduce(next, arr, fn, i);
911
+ }
912
+ result = next;
913
+ }
914
+ return result;
915
+ }
916
+ async function chainRemainingReduce(currentPromise, arr, fn, startIndex) {
917
+ let result = await currentPromise;
918
+ for (let i = startIndex + 1; i < arr.length; i++) {
919
+ result = await fn(result, arr[i], i);
920
+ }
921
+ return result;
922
+ }
923
+ /**
924
+ * Like Array.forEach but handles MaybePromise callbacks sequentially.
925
+ * In the sync case, runs as a simple loop. Switches to async only when needed.
926
+ */
927
+ function forEachSequential(arr, fn) {
928
+ for (let i = 0; i < arr.length; i++) {
929
+ const result = fn(arr[i], i);
930
+ if (result instanceof Promise) {
931
+ return chainRemainingForEach(result, arr, fn, i);
932
+ }
933
+ }
934
+ }
935
+ async function chainRemainingForEach(currentPromise, arr, fn, startIndex) {
936
+ await currentPromise;
937
+ for (let i = startIndex + 1; i < arr.length; i++) {
938
+ await fn(arr[i], i);
939
+ }
940
+ }
941
+ /**
942
+ * Try/catch that handles MaybePromise values correctly.
943
+ * If tryFn returns a Promise, catches both sync throws and Promise rejections.
944
+ */
945
+ function tryCatch(tryFn, catchFn) {
946
+ try {
947
+ const result = tryFn();
948
+ if (result instanceof Promise) {
949
+ return result.catch(catchFn);
950
+ }
951
+ return result;
952
+ }
953
+ catch (error) {
954
+ return catchFn(error);
955
+ }
956
+ }
957
+ /**
958
+ * Like Array.some but handles MaybePromise callbacks sequentially.
959
+ * Returns the first truthy MaybePromise result, or false.
960
+ */
961
+ function someSequential(arr, fn) {
962
+ for (let i = 0; i < arr.length; i++) {
963
+ const result = fn(arr[i], i);
964
+ if (result instanceof Promise) {
965
+ return chainRemainingSome(result, arr, fn, i);
966
+ }
967
+ if (result)
968
+ return true;
969
+ }
970
+ return false;
971
+ }
972
+ async function chainRemainingSome(currentPromise, arr, fn, startIndex) {
973
+ if (await currentPromise)
974
+ return true;
975
+ for (let i = startIndex + 1; i < arr.length; i++) {
976
+ if (await fn(arr[i], i))
977
+ return true;
978
+ }
979
+ return false;
980
+ }
981
+ /**
982
+ * Like Array.every but handles MaybePromise callbacks sequentially.
983
+ * Returns false as soon as a falsy result is found.
984
+ */
985
+ function everySequential(arr, fn) {
986
+ for (let i = 0; i < arr.length; i++) {
987
+ const result = fn(arr[i], i);
988
+ if (result instanceof Promise) {
989
+ return chainRemainingEvery(result, arr, fn, i);
990
+ }
991
+ if (!result)
992
+ return false;
993
+ }
994
+ return true;
995
+ }
996
+ async function chainRemainingEvery(currentPromise, arr, fn, startIndex) {
997
+ if (!await currentPromise)
998
+ return false;
999
+ for (let i = startIndex + 1; i < arr.length; i++) {
1000
+ if (!await fn(arr[i], i))
1001
+ return false;
1002
+ }
1003
+ return true;
1004
+ }
1005
+ /**
1006
+ * Like Array.filter but handles MaybePromise callbacks sequentially.
1007
+ * Returns the filtered array.
1008
+ */
1009
+ function filterSequential(arr, fn) {
1010
+ const results = [];
1011
+ for (let i = 0; i < arr.length; i++) {
1012
+ const result = fn(arr[i], i);
1013
+ if (result instanceof Promise) {
1014
+ return chainRemainingFilter(result, results, arr, fn, i);
1015
+ }
1016
+ if (result)
1017
+ results.push(arr[i]);
1018
+ }
1019
+ return results;
1020
+ }
1021
+ async function chainRemainingFilter(currentPromise, results, arr, fn, startIndex) {
1022
+ if (await currentPromise)
1023
+ results.push(arr[startIndex]);
1024
+ for (let i = startIndex + 1; i < arr.length; i++) {
1025
+ if (await fn(arr[i], i))
1026
+ results.push(arr[i]);
1027
+ }
1028
+ return results;
1029
+ }
1030
+ /**
1031
+ * Like Array.findIndex but handles MaybePromise callbacks sequentially.
1032
+ * Returns -1 if no element matches.
1033
+ */
1034
+ function findIndexSequential(arr, fn) {
1035
+ for (let i = 0; i < arr.length; i++) {
1036
+ const result = fn(arr[i], i);
1037
+ if (result instanceof Promise) {
1038
+ return chainRemainingFindIndex(result, arr, fn, i);
1039
+ }
1040
+ if (result)
1041
+ return i;
1042
+ }
1043
+ return -1;
1044
+ }
1045
+ async function chainRemainingFindIndex(currentPromise, arr, fn, startIndex) {
1046
+ if (await currentPromise)
1047
+ return startIndex;
1048
+ for (let i = startIndex + 1; i < arr.length; i++) {
1049
+ if (await fn(arr[i], i))
1050
+ return i;
1051
+ }
1052
+ return -1;
1053
+ }
1054
+
861
1055
  function mapObjects({ colls, contextStack, executeFunction, fn, sourceCodeInfo, }) {
862
1056
  assertObj(colls[0], sourceCodeInfo);
863
1057
  const keys = Object.keys(colls[0]);
@@ -877,10 +1071,13 @@ function mapObjects({ colls, contextStack, executeFunction, fn, sourceCodeInfo,
877
1071
  params[key].push(value);
878
1072
  });
879
1073
  });
880
- return keys.reduce((result, key) => {
881
- result[key] = executeFunction(fn, params[key], contextStack, sourceCodeInfo);
882
- return result;
883
- }, {});
1074
+ const initialObj = {};
1075
+ return reduceSequential(keys, (result, key) => {
1076
+ return chain(executeFunction(fn, params[key], contextStack, sourceCodeInfo), (value) => {
1077
+ result[key] = value;
1078
+ return result;
1079
+ });
1080
+ }, initialObj);
884
1081
  }
885
1082
  function get$1(coll, key) {
886
1083
  if (isObj(coll)) {
@@ -919,21 +1116,33 @@ const collectionNormalExpression = {
919
1116
  assertColl(coll, sourceCodeInfo);
920
1117
  assertFunctionLike(fn, sourceCodeInfo);
921
1118
  if (Array.isArray(coll)) {
922
- const result = coll.filter(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
923
- return result;
1119
+ return reduceSequential(coll, (result, elem) => {
1120
+ return chain(executeFunction(fn, [elem], contextStack, sourceCodeInfo), (keep) => {
1121
+ if (keep)
1122
+ result.push(elem);
1123
+ return result;
1124
+ });
1125
+ }, []);
924
1126
  }
925
1127
  if (isString(coll)) {
926
- return coll
927
- .split('')
928
- .filter(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo))
929
- .join('');
930
- }
931
- return Object.entries(coll)
932
- .filter(([, value]) => executeFunction(fn, [value], contextStack, sourceCodeInfo))
933
- .reduce((result, [key, value]) => {
934
- result[key] = value;
935
- return result;
936
- }, {});
1128
+ const chars = coll.split('');
1129
+ return chain(reduceSequential(chars, (result, elem) => {
1130
+ return chain(executeFunction(fn, [elem], contextStack, sourceCodeInfo), (keep) => {
1131
+ if (keep)
1132
+ result.push(elem);
1133
+ return result;
1134
+ });
1135
+ }, []), filtered => filtered.join(''));
1136
+ }
1137
+ const entries = Object.entries(coll);
1138
+ const initialObj = {};
1139
+ return reduceSequential(entries, (result, [key, value]) => {
1140
+ return chain(executeFunction(fn, [value], contextStack, sourceCodeInfo), (keep) => {
1141
+ if (keep)
1142
+ result[key] = value;
1143
+ return result;
1144
+ });
1145
+ }, initialObj);
937
1146
  },
938
1147
  arity: toFixedArity(2),
939
1148
  docs: {
@@ -996,12 +1205,14 @@ filter(
996
1205
  for (let i = 0; i < len; i++) {
997
1206
  paramArray.push(seqs.map(seq => seq[i]));
998
1207
  }
999
- const mapped = paramArray.map(p => executeFunction(fn, p, contextStack, sourceCodeInfo));
1208
+ const mapped = mapSequential(paramArray, p => executeFunction(fn, p, contextStack, sourceCodeInfo));
1000
1209
  if (!isStr) {
1001
1210
  return mapped;
1002
1211
  }
1003
- mapped.forEach(char => assertString(char, sourceCodeInfo));
1004
- return mapped.join('');
1212
+ return chain(mapped, (resolvedMapped) => {
1213
+ resolvedMapped.forEach(char => assertString(char, sourceCodeInfo));
1214
+ return resolvedMapped.join('');
1215
+ });
1005
1216
  },
1006
1217
  arity: { min: 2 },
1007
1218
  docs: {
@@ -1036,21 +1247,21 @@ filter(
1036
1247
  assertString(initial, sourceCodeInfo);
1037
1248
  if (coll.length === 0)
1038
1249
  return initial;
1039
- return coll.split('').reduce((result, elem) => {
1250
+ return reduceSequential(coll.split(''), (result, elem) => {
1040
1251
  return executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
1041
1252
  }, initial);
1042
1253
  }
1043
1254
  else if (Array.isArray(coll)) {
1044
1255
  if (coll.length === 0)
1045
1256
  return initial;
1046
- return coll.reduce((result, elem) => {
1257
+ return reduceSequential(coll, (result, elem) => {
1047
1258
  return executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
1048
1259
  }, initial);
1049
1260
  }
1050
1261
  else {
1051
1262
  if (Object.keys(coll).length === 0)
1052
1263
  return initial;
1053
- return Object.entries(coll).reduce((result, [, elem]) => {
1264
+ return reduceSequential(Object.entries(coll), (result, [, elem]) => {
1054
1265
  return executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
1055
1266
  }, initial);
1056
1267
  }
@@ -1490,7 +1701,7 @@ flatten([
1490
1701
  evaluate: ([arr, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
1491
1702
  assertArray(arr, sourceCodeInfo);
1492
1703
  assertFunctionLike(fn, sourceCodeInfo);
1493
- return arr.map(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo)).flat(1);
1704
+ return chain(mapSequential(arr, elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo)), mapped => mapped.flat(1));
1494
1705
  },
1495
1706
  arity: toFixedArity(2),
1496
1707
  docs: {
@@ -1527,13 +1738,11 @@ mapcat(
1527
1738
  assertArray(arr, sourceCodeInfo);
1528
1739
  assertNumber(windowSize, sourceCodeInfo, { integer: true, lte: arr.length });
1529
1740
  assertFunctionLike(fn, sourceCodeInfo);
1530
- const result = [];
1741
+ const windows = [];
1531
1742
  for (let i = 0; i <= arr.length - windowSize; i++) {
1532
- const window = arr.slice(i, i + windowSize);
1533
- const value = executeFunction(fn, [window], contextStack, sourceCodeInfo);
1534
- result.push(value);
1743
+ windows.push(arr.slice(i, i + windowSize));
1535
1744
  }
1536
- return result;
1745
+ return mapSequential(windows, window => executeFunction(fn, [window], contextStack, sourceCodeInfo));
1537
1746
  },
1538
1747
  arity: toFixedArity(3),
1539
1748
  docs: {
@@ -1558,12 +1767,11 @@ mapcat(
1558
1767
  evaluate: ([arr, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
1559
1768
  assertArray(arr, sourceCodeInfo);
1560
1769
  assertFunctionLike(fn, sourceCodeInfo);
1561
- const result = [];
1770
+ const subArrays = [];
1562
1771
  for (let i = 0; i < arr.length; i += 1) {
1563
- const subArr = arr.slice(0, i + 1);
1564
- result.push(executeFunction(fn, [subArr], contextStack, sourceCodeInfo));
1772
+ subArrays.push(arr.slice(0, i + 1));
1565
1773
  }
1566
- return result;
1774
+ return mapSequential(subArrays, subArr => executeFunction(fn, [subArr], contextStack, sourceCodeInfo));
1567
1775
  },
1568
1776
  arity: toFixedArity(2),
1569
1777
  docs: {
@@ -1922,7 +2130,7 @@ For string $seq returns all but the first characters in $seq.`,
1922
2130
  { argumentNames: ['seq', 'start', 'stop'] },
1923
2131
  ],
1924
2132
  description: 'Returns a copy of a portion of $seq from index $start (inclusive) to $stop (exclusive).',
1925
- seeAlso: ['sequence.take', 'sequence.drop', 'sequence.splice', 'nth'],
2133
+ seeAlso: ['take', 'drop', 'sequence.splice', 'nth'],
1926
2134
  examples: [
1927
2135
  '[1, 2, 3, 4, 5] slice 2',
1928
2136
  'slice([1, 2, 3, 4, 5], 2, 4)',
@@ -1938,9 +2146,14 @@ For string $seq returns all but the first characters in $seq.`,
1938
2146
  assertSeq(seq, sourceCodeInfo);
1939
2147
  if (seq.length === 0)
1940
2148
  return null;
1941
- if (typeof seq === 'string')
1942
- return seq.split('').find(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo)) ?? null;
1943
- return toAny(seq.find(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo)));
2149
+ const items = typeof seq === 'string' ? seq.split('') : seq;
2150
+ return reduceSequential(items, (found, elem) => {
2151
+ if (found !== null)
2152
+ return found;
2153
+ return chain(executeFunction(fn, [elem], contextStack, sourceCodeInfo), (result) => {
2154
+ return result ? toAny(elem) : null;
2155
+ });
2156
+ }, null);
1944
2157
  },
1945
2158
  arity: toFixedArity(2),
1946
2159
  docs: {
@@ -1985,7 +2198,7 @@ some(
1985
2198
  },
1986
2199
  },
1987
2200
  'sort': {
1988
- evaluate: (params, sourceCodeInfo, contextStack, { executeFunction }) => {
2201
+ evaluate: (params, sourceCodeInfo, _contextStack, { executeFunction: _executeFunction }) => {
1989
2202
  const [seq] = params;
1990
2203
  const defaultComparer = params.length === 1;
1991
2204
  const comparer = defaultComparer ? null : params[1];
@@ -1997,8 +2210,12 @@ some(
1997
2210
  }
1998
2211
  else {
1999
2212
  assertFunctionLike(comparer, sourceCodeInfo);
2213
+ // Note: sort comparator must be synchronous — async comparators would need a different approach
2000
2214
  result.sort((a, b) => {
2001
- const compareValue = executeFunction(comparer, [a, b], contextStack, sourceCodeInfo);
2215
+ const compareValue = _executeFunction(comparer, [a, b], _contextStack, sourceCodeInfo);
2216
+ if (compareValue instanceof Promise) {
2217
+ throw new TypeError('Async functions cannot be used as sort comparators');
2218
+ }
2002
2219
  assertNumber(compareValue, sourceCodeInfo, { finite: true });
2003
2220
  return compareValue;
2004
2221
  });
@@ -2016,7 +2233,11 @@ some(
2016
2233
  else {
2017
2234
  result.sort((a, b) => {
2018
2235
  assertFunctionLike(comparer, sourceCodeInfo);
2019
- const compareValue = executeFunction(comparer, [a, b], contextStack, sourceCodeInfo);
2236
+ // Note: sort comparator must be synchronous
2237
+ const compareValue = _executeFunction(comparer, [a, b], _contextStack, sourceCodeInfo);
2238
+ if (compareValue instanceof Promise) {
2239
+ throw new TypeError('Async functions cannot be used as sort comparators');
2240
+ }
2020
2241
  assertNumber(compareValue, sourceCodeInfo, { finite: true });
2021
2242
  return compareValue;
2022
2243
  });
@@ -2051,6 +2272,191 @@ sort(
2051
2272
  sort(
2052
2273
  [3, 1, 2],
2053
2274
  (a, b) -> cond case a > b then -1 case a < b then 1 case true then -1 end
2275
+ )`,
2276
+ ],
2277
+ },
2278
+ },
2279
+ 'take': {
2280
+ evaluate: ([input, n], sourceCodeInfo) => {
2281
+ assertNumber(n, sourceCodeInfo);
2282
+ assertSeq(input, sourceCodeInfo);
2283
+ const num = Math.max(Math.ceil(n), 0);
2284
+ return input.slice(0, num);
2285
+ },
2286
+ arity: toFixedArity(2),
2287
+ docs: {
2288
+ category: 'sequence',
2289
+ returns: { type: 'sequence' },
2290
+ args: {
2291
+ a: { type: 'sequence' },
2292
+ b: { type: 'integer' },
2293
+ n: { type: 'integer' },
2294
+ seq: { type: 'sequence' },
2295
+ },
2296
+ variants: [{ argumentNames: ['seq', 'n'] }],
2297
+ description: 'Constructs a new array/string with the $n first elements from $seq.',
2298
+ seeAlso: ['take-last', 'take-while', 'drop', 'slice', 'sequence.split-at'],
2299
+ examples: [
2300
+ 'take([1, 2, 3, 4, 5], 3)',
2301
+ '[1, 2, 3, 4, 5] take 3',
2302
+ 'take([1, 2, 3, 4, 5], 0)',
2303
+ 'take("Albert", 2)',
2304
+ 'take("Albert", 50)',
2305
+ ],
2306
+ },
2307
+ },
2308
+ 'take-last': {
2309
+ evaluate: ([array, n], sourceCodeInfo) => {
2310
+ assertSeq(array, sourceCodeInfo);
2311
+ assertNumber(n, sourceCodeInfo);
2312
+ const num = Math.max(Math.ceil(n), 0);
2313
+ const from = array.length - num;
2314
+ return array.slice(from);
2315
+ },
2316
+ arity: toFixedArity(2),
2317
+ docs: {
2318
+ category: 'sequence',
2319
+ returns: { type: 'sequence' },
2320
+ args: {
2321
+ a: { type: 'sequence' },
2322
+ b: { type: 'integer' },
2323
+ n: { type: 'integer' },
2324
+ seq: { type: 'sequence' },
2325
+ },
2326
+ variants: [{ argumentNames: ['seq', 'n'] }],
2327
+ description: 'Constructs a new array with the $n last elements from $seq.',
2328
+ seeAlso: ['take', 'drop-last'],
2329
+ examples: [
2330
+ 'take-last([1, 2, 3, 4, 5], 3)',
2331
+ '[1, 2, 3, 4, 5] take-last 3',
2332
+ 'take-last([1, 2, 3, 4, 5], 0)',
2333
+ ],
2334
+ },
2335
+ },
2336
+ 'drop': {
2337
+ evaluate: ([input, n], sourceCodeInfo) => {
2338
+ assertNumber(n, sourceCodeInfo);
2339
+ const num = Math.max(Math.ceil(n), 0);
2340
+ assertSeq(input, sourceCodeInfo);
2341
+ return input.slice(num);
2342
+ },
2343
+ arity: toFixedArity(2),
2344
+ docs: {
2345
+ category: 'sequence',
2346
+ returns: { type: 'sequence' },
2347
+ args: {
2348
+ a: { type: 'sequence' },
2349
+ b: { type: 'integer' },
2350
+ seq: { type: 'sequence' },
2351
+ n: { type: 'integer' },
2352
+ },
2353
+ variants: [{ argumentNames: ['seq', 'n'] }],
2354
+ description: 'Constructs a new array/string with the $n first elements dropped from $seq.',
2355
+ seeAlso: ['drop-last', 'drop-while', 'take', 'slice', 'sequence.split-at'],
2356
+ examples: [
2357
+ 'drop([1, 2, 3, 4, 5], 3)',
2358
+ '[1, 2, 3, 4, 5] drop 0',
2359
+ 'drop("Albert", 2)',
2360
+ 'drop("Albert", 50)',
2361
+ ],
2362
+ },
2363
+ },
2364
+ 'drop-last': {
2365
+ evaluate: ([array, n], sourceCodeInfo) => {
2366
+ assertSeq(array, sourceCodeInfo);
2367
+ assertNumber(n, sourceCodeInfo);
2368
+ const num = Math.max(Math.ceil(n), 0);
2369
+ const from = array.length - num;
2370
+ return array.slice(0, from);
2371
+ },
2372
+ arity: toFixedArity(2),
2373
+ docs: {
2374
+ category: 'sequence',
2375
+ returns: { type: 'sequence' },
2376
+ args: {
2377
+ a: { type: 'sequence' },
2378
+ b: { type: 'integer' },
2379
+ seq: { type: 'sequence' },
2380
+ n: { type: 'integer' },
2381
+ },
2382
+ variants: [{ argumentNames: ['seq', 'n'] }],
2383
+ description: 'Constructs a new array with the $n last elements dropped from $seq.',
2384
+ seeAlso: ['drop', 'take-last'],
2385
+ examples: [
2386
+ 'drop-last([1, 2, 3, 4, 5], 3)',
2387
+ '[1, 2, 3, 4, 5] drop-last 3',
2388
+ 'drop-last([1, 2, 3, 4, 5], 0)',
2389
+ ],
2390
+ },
2391
+ },
2392
+ 'take-while': {
2393
+ evaluate: ([seq, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
2394
+ assertSeq(seq, sourceCodeInfo);
2395
+ assertFunctionLike(fn, sourceCodeInfo);
2396
+ const arr = typeof seq === 'string' ? seq.split('') : Array.from(seq);
2397
+ // Find the first index where the predicate is false
2398
+ return chain(findIndexSequential(arr, elem => chain(executeFunction(fn, [elem], contextStack, sourceCodeInfo), result => !result)), (index) => {
2399
+ const taken = index === -1 ? arr : arr.slice(0, index);
2400
+ return typeof seq === 'string' ? taken.join('') : taken;
2401
+ });
2402
+ },
2403
+ arity: toFixedArity(2),
2404
+ docs: {
2405
+ category: 'sequence',
2406
+ returns: { type: 'sequence' },
2407
+ args: {
2408
+ a: { type: 'sequence' },
2409
+ b: { type: 'function' },
2410
+ seq: { type: 'sequence' },
2411
+ fun: { type: 'function' },
2412
+ },
2413
+ variants: [{ argumentNames: ['seq', 'fun'] }],
2414
+ description: 'Returns the members of $seq in order, stopping before the first one for which `predicate` returns a falsy value.',
2415
+ seeAlso: ['take', 'drop-while', 'sequence.split-with'],
2416
+ examples: [
2417
+ `take-while(
2418
+ [1, 2, 3, 2, 1],
2419
+ -> $ < 3
2420
+ )`,
2421
+ `take-while(
2422
+ [1, 2, 3, 2, 1],
2423
+ -> $ > 3
2424
+ )`,
2425
+ ],
2426
+ },
2427
+ },
2428
+ 'drop-while': {
2429
+ evaluate: ([seq, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
2430
+ assertSeq(seq, sourceCodeInfo);
2431
+ assertFunctionLike(fn, sourceCodeInfo);
2432
+ const arr = Array.isArray(seq) ? seq : seq.split('');
2433
+ return chain(findIndexSequential(arr, elem => chain(executeFunction(fn, [elem], contextStack, sourceCodeInfo), result => !result)), (from) => {
2434
+ if (from === -1)
2435
+ return typeof seq === 'string' ? '' : [];
2436
+ return typeof seq === 'string' ? arr.slice(from).join('') : seq.slice(from);
2437
+ });
2438
+ },
2439
+ arity: toFixedArity(2),
2440
+ docs: {
2441
+ category: 'sequence',
2442
+ returns: { type: 'sequence' },
2443
+ args: {
2444
+ a: { type: 'sequence' },
2445
+ b: { type: 'function' },
2446
+ seq: { type: 'sequence' },
2447
+ fun: { type: 'function' },
2448
+ },
2449
+ variants: [{ argumentNames: ['seq', 'fun'] }],
2450
+ description: 'Returns the members of $seq in order, skipping the fist elements for witch the `predicate` returns a truethy value.',
2451
+ seeAlso: ['drop', 'take-while', 'sequence.split-with'],
2452
+ examples: [
2453
+ `drop-while(
2454
+ [1, 2, 3, 2, 1],
2455
+ -> $ < 3
2456
+ )`,
2457
+ `drop-while(
2458
+ [1, 2, 3, 2, 1],
2459
+ -> $ > 3
2054
2460
  )`,
2055
2461
  ],
2056
2462
  },
@@ -2987,7 +3393,7 @@ const miscNormalExpression = {
2987
3393
  { argumentNames: ['x', 'ys'] },
2988
3394
  ],
2989
3395
  description: 'Returns `true` if all `values` are structaul equal to each other, otherwise result is `false`.',
2990
- seeAlso: ['', 'identical?'],
3396
+ seeAlso: ['!=', 'identical?'],
2991
3397
  examples: [
2992
3398
  '1 == 1',
2993
3399
  '[1, 2] == [1, 2]',
@@ -3009,7 +3415,7 @@ const miscNormalExpression = {
3009
3415
  ],
3010
3416
  },
3011
3417
  },
3012
- '': {
3418
+ '!=': {
3013
3419
  evaluate: (params, sourceCodeInfo) => {
3014
3420
  return !isEqual(params, sourceCodeInfo);
3015
3421
  },
@@ -3027,15 +3433,15 @@ const miscNormalExpression = {
3027
3433
  { argumentNames: ['x'] },
3028
3434
  { argumentNames: ['x', 'ys'] },
3029
3435
  ],
3030
- description: 'Returns `true` if all `values` are not equal to each other, otherwise result is `false`. `( a b c)` is same as `(! (== a b c))`.',
3436
+ description: 'Returns `true` if all `values` are not equal to each other, otherwise result is `false`. `(!= a b c)` is same as `(not (== a b c))`.',
3031
3437
  seeAlso: ['==', 'identical?'],
3032
3438
  examples: [
3033
- '1 2',
3034
- '3 3',
3035
- '(3)',
3036
- '(3, 3, 2)',
3037
- '("3", "2", "1", "0",)',
3038
- '(0, -0)',
3439
+ '1 != 2',
3440
+ '3 != 3',
3441
+ '!=(3)',
3442
+ '!=(3, 3, 2)',
3443
+ '!=("3", "2", "1", "0",)',
3444
+ '!=(0, -0)',
3039
3445
  ],
3040
3446
  },
3041
3447
  },
@@ -3053,7 +3459,7 @@ const miscNormalExpression = {
3053
3459
  },
3054
3460
  variants: [{ argumentNames: ['a', 'b'] }],
3055
3461
  description: 'Returns true if $a and $b are referential equal.',
3056
- seeAlso: ['==', ''],
3462
+ seeAlso: ['==', '!='],
3057
3463
  examples: [
3058
3464
  'identical?({ a: 10, b: 20 }, { b: 20, a: 10 })',
3059
3465
  'identical?([1, true, null], [1, true, null])',
@@ -3204,7 +3610,7 @@ const miscNormalExpression = {
3204
3610
  ],
3205
3611
  },
3206
3612
  },
3207
- '!': {
3613
+ 'not': {
3208
3614
  evaluate: ([first]) => !first,
3209
3615
  arity: toFixedArity(1),
3210
3616
  docs: {
@@ -3215,13 +3621,13 @@ const miscNormalExpression = {
3215
3621
  description: 'Computes logical negation. Note that any other $x than `false`, `0`, `null` and `\'\'` is truthy.',
3216
3622
  seeAlso: ['boolean'],
3217
3623
  examples: [
3218
- '!(3)',
3219
- '!(true)',
3220
- '!("A string")',
3221
- '!(0)',
3222
- '!(false)',
3223
- '!(null)',
3224
- '!("")',
3624
+ 'not(3)',
3625
+ 'not(true)',
3626
+ 'not("A string")',
3627
+ 'not(0)',
3628
+ 'not(false)',
3629
+ 'not(null)',
3630
+ 'not("")',
3225
3631
  ],
3226
3632
  },
3227
3633
  },
@@ -3302,7 +3708,7 @@ const miscNormalExpression = {
3302
3708
  args: { x: { type: 'any' } },
3303
3709
  variants: [{ argumentNames: ['x'] }],
3304
3710
  description: 'Coerces $x to boolean.',
3305
- seeAlso: ['!', 'boolean?', 'true?', 'false?'],
3711
+ seeAlso: ['not', 'boolean?', 'true?', 'false?'],
3306
3712
  examples: [
3307
3713
  'boolean(0)',
3308
3714
  'boolean(1)',
@@ -3611,17 +4017,23 @@ If no arguments are provided \`null\` is returned.`,
3611
4017
  const rest = params.slice(1, -1);
3612
4018
  assertObj(first, sourceCodeInfo);
3613
4019
  assertFunctionLike(fn, sourceCodeInfo);
3614
- return rest.reduce((result, obj) => {
4020
+ return reduceSequential(rest, (result, obj) => {
3615
4021
  assertObj(obj, sourceCodeInfo);
3616
- Object.entries(obj).forEach((entry) => {
4022
+ const entries = Object.entries(obj);
4023
+ return chain(reduceSequential(entries, (res, entry) => {
3617
4024
  const key = asString(entry[0], sourceCodeInfo);
3618
4025
  const val = toAny(entry[1]);
3619
- if (collHasKey(result, key))
3620
- result[key] = executeFunction(fn, [result[key], val], contextStack, sourceCodeInfo);
3621
- else
3622
- result[key] = val;
3623
- });
3624
- return result;
4026
+ if (collHasKey(res, key)) {
4027
+ return chain(executeFunction(fn, [res[key], val], contextStack, sourceCodeInfo), (merged) => {
4028
+ res[key] = merged;
4029
+ return res;
4030
+ });
4031
+ }
4032
+ else {
4033
+ res[key] = val;
4034
+ return res;
4035
+ }
4036
+ }, result), r => r);
3625
4037
  }, { ...first });
3626
4038
  },
3627
4039
  arity: { min: 2 },
@@ -5043,13 +5455,11 @@ const andSpecialExpression = {
5043
5455
  arity: {},
5044
5456
  docs: docs$f,
5045
5457
  evaluate: (node, contextStack, { evaluateNode }) => {
5046
- let value = true;
5047
- for (const param of node[1][1]) {
5048
- value = evaluateNode(param, contextStack);
5049
- if (!value)
5050
- break;
5051
- }
5052
- return value;
5458
+ return reduceSequential(node[1][1], (acc, param) => {
5459
+ if (!acc)
5460
+ return acc;
5461
+ return evaluateNode(param, contextStack);
5462
+ }, true);
5053
5463
  },
5054
5464
  evaluateAsNormalExpression: (params, sourceCodeInfo) => {
5055
5465
  let value = true;
@@ -5095,13 +5505,17 @@ const condSpecialExpression = {
5095
5505
  docs: docs$e,
5096
5506
  evaluate: (node, contextStack, { evaluateNode }) => {
5097
5507
  const params = node[1][1];
5098
- for (const [test, form] of params) {
5099
- const value = evaluateNode(test, contextStack);
5100
- if (!value)
5101
- continue;
5102
- return evaluateNode(form, contextStack);
5508
+ function processCase(index) {
5509
+ if (index >= params.length)
5510
+ return null;
5511
+ const [test, form] = params[index];
5512
+ return chain(evaluateNode(test, contextStack), (value) => {
5513
+ if (!value)
5514
+ return processCase(index + 1);
5515
+ return evaluateNode(form, contextStack);
5516
+ });
5103
5517
  }
5104
- return null;
5518
+ return processCase(0);
5105
5519
  },
5106
5520
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => getUndefinedSymbols(node[1][1].flat(), contextStack, builtin, evaluateNode),
5107
5521
  };
@@ -5139,14 +5553,20 @@ const switchSpecialExpression = {
5139
5553
  docs: docs$d,
5140
5554
  evaluate: (node, contextStack, { evaluateNode }) => {
5141
5555
  const [, switchValueNode, cases] = node[1];
5142
- const switchValue = evaluateNode(switchValueNode, contextStack);
5143
- for (const [test, form] of cases) {
5144
- const value = evaluateNode(test, contextStack);
5145
- if (value === switchValue) {
5146
- return evaluateNode(form, contextStack);
5556
+ return chain(evaluateNode(switchValueNode, contextStack), (switchValue) => {
5557
+ function processCase(index) {
5558
+ if (index >= cases.length)
5559
+ return null;
5560
+ const [test, form] = cases[index];
5561
+ return chain(evaluateNode(test, contextStack), (value) => {
5562
+ if (value === switchValue) {
5563
+ return evaluateNode(form, contextStack);
5564
+ }
5565
+ return processCase(index + 1);
5566
+ });
5147
5567
  }
5148
- }
5149
- return null;
5568
+ return processCase(0);
5569
+ });
5150
5570
  },
5151
5571
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => getUndefinedSymbols([node[1][1], ...node[1][2].flat()], contextStack, builtin, evaluateNode),
5152
5572
  };
@@ -5226,37 +5646,47 @@ function walkDefaults(bindingTarget, onDefault) {
5226
5646
  function evaluateBindingNodeValues(target, value, evaluate) {
5227
5647
  const sourceCodeInfo = target[2];
5228
5648
  const record = {};
5229
- createRecord(target, value, evaluate, sourceCodeInfo, record);
5230
- return record;
5649
+ return chain(createRecord(target, value, evaluate, sourceCodeInfo, record), () => record);
5231
5650
  }
5232
5651
  function createRecord(bindingTarget, value, evaluate, sourceCodeInfo, record) {
5233
5652
  if (bindingTarget[0] === bindingTargetTypes.object) {
5234
5653
  assertUnknownRecord(value, sourceCodeInfo);
5235
5654
  const capturedKeys = new Set();
5236
5655
  let restElement;
5237
- Object.entries(bindingTarget[1][0]).forEach(([key, element]) => {
5656
+ const entries = Object.entries(bindingTarget[1][0]);
5657
+ return chain(forEachSequential(entries, ([key, element]) => {
5238
5658
  if (element[0] === bindingTargetTypes.rest) {
5239
5659
  restElement = element;
5240
5660
  return;
5241
5661
  }
5242
5662
  capturedKeys.add(key);
5243
- const val = (value[key] !== undefined ? value[key] : element[1][1] && evaluate(element[1][1])) ?? null;
5244
- assertAny(val, sourceCodeInfo);
5245
- createRecord(element, val, evaluate, sourceCodeInfo, record);
5663
+ const existingVal = value[key];
5664
+ const maybeVal = existingVal !== undefined
5665
+ ? existingVal
5666
+ : element[1][1]
5667
+ ? evaluate(element[1][1])
5668
+ : null;
5669
+ return chain(maybeVal, (resolvedVal) => {
5670
+ const val = resolvedVal ?? null;
5671
+ assertAny(val, sourceCodeInfo);
5672
+ return createRecord(element, val, evaluate, sourceCodeInfo, record);
5673
+ });
5674
+ }), () => {
5675
+ if (restElement) {
5676
+ const restValues = Object.entries(value)
5677
+ .filter(([key]) => !capturedKeys.has(key))
5678
+ .reduce((acc, [key, val]) => {
5679
+ acc[key] = asAny(val);
5680
+ return acc;
5681
+ }, {});
5682
+ record[restElement[1][0]] = restValues;
5683
+ }
5246
5684
  });
5247
- if (restElement) {
5248
- const restValues = Object.entries(value)
5249
- .filter(([key]) => !capturedKeys.has(key))
5250
- .reduce((acc, [key, val]) => {
5251
- acc[key] = asAny(val);
5252
- return acc;
5253
- }, {});
5254
- record[restElement[1][0]] = restValues;
5255
- }
5256
5685
  }
5257
5686
  else if (bindingTarget[0] === bindingTargetTypes.array) {
5258
5687
  let restIndex = null;
5259
5688
  assertArray(value, sourceCodeInfo);
5689
+ const elements = [];
5260
5690
  for (let index = 0; index < bindingTarget[1][0].length; index += 1) {
5261
5691
  const element = bindingTarget[1][0][index] ?? null;
5262
5692
  if (element === null) {
@@ -5266,15 +5696,27 @@ function createRecord(bindingTarget, value, evaluate, sourceCodeInfo, record) {
5266
5696
  restIndex = index;
5267
5697
  break;
5268
5698
  }
5269
- const val = (value[index] !== undefined ? value[index] : element[1][1] && evaluate(element[1][1])) ?? null;
5270
- assertAny(val, sourceCodeInfo);
5271
- createRecord(element, val, evaluate, sourceCodeInfo, record);
5272
- }
5273
- if (restIndex !== null) {
5274
- const restValues = value.slice(restIndex);
5275
- const restElement = bindingTarget[1][0][restIndex];
5276
- record[restElement[1][0]] = restValues;
5277
- }
5699
+ elements.push({ element, index });
5700
+ }
5701
+ return chain(forEachSequential(elements, ({ element, index }) => {
5702
+ const existingVal = value[index];
5703
+ const maybeVal = existingVal !== undefined
5704
+ ? existingVal
5705
+ : element[1][1]
5706
+ ? evaluate(element[1][1])
5707
+ : null;
5708
+ return chain(maybeVal, (resolvedVal) => {
5709
+ const val = resolvedVal ?? null;
5710
+ assertAny(val, sourceCodeInfo);
5711
+ return createRecord(element, val, evaluate, sourceCodeInfo, record);
5712
+ });
5713
+ }), () => {
5714
+ if (restIndex !== null) {
5715
+ const restValues = value.slice(restIndex);
5716
+ const restElement = bindingTarget[1][0][restIndex];
5717
+ record[restElement[1][0]] = restValues;
5718
+ }
5719
+ });
5278
5720
  }
5279
5721
  else if (bindingTarget[0] === bindingTargetTypes.rest) {
5280
5722
  record[bindingTarget[1][0]] = asAny(value);
@@ -5322,10 +5764,12 @@ const defSpecialExpression = {
5322
5764
  const bindingNode = node[1][1];
5323
5765
  const target = bindingNode[1][0];
5324
5766
  const value = bindingNode[1][1];
5325
- const bindingValue = evaluateNode(value, contextStack);
5326
- const values = evaluateBindingNodeValues(target, bindingValue, Node => evaluateNode(Node, contextStack));
5327
- contextStack.exportValues(values, target[2]);
5328
- return bindingValue;
5767
+ return chain(evaluateNode(value, contextStack), (bindingValue) => {
5768
+ return chain(evaluateBindingNodeValues(target, bindingValue, Node => evaluateNode(Node, contextStack)), (values) => {
5769
+ contextStack.exportValues(values, target[2]);
5770
+ return bindingValue;
5771
+ });
5772
+ });
5329
5773
  },
5330
5774
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => {
5331
5775
  const bindingNode = node[1][1];
@@ -5362,10 +5806,7 @@ const doSpecialExpression = {
5362
5806
  evaluate: (node, contextStack, { evaluateNode }) => {
5363
5807
  const newContext = {};
5364
5808
  const newContextStack = contextStack.create(newContext);
5365
- let result = null;
5366
- for (const form of node[1][1])
5367
- result = evaluateNode(form, newContextStack);
5368
- return result;
5809
+ return reduceSequential(node[1][1], (_acc, form) => evaluateNode(form, newContextStack), null);
5369
5810
  },
5370
5811
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => {
5371
5812
  return getUndefinedSymbols(node[1][1], contextStack.create({}), builtin, evaluateNode);
@@ -5460,13 +5901,15 @@ const ifSpecialExpression = {
5460
5901
  docs: docs$a,
5461
5902
  evaluate: (node, contextStack, { evaluateNode }) => {
5462
5903
  const [conditionNode, trueNode, falseNode] = node[1][1];
5463
- if (evaluateNode(conditionNode, contextStack)) {
5464
- return evaluateNode(trueNode, contextStack);
5465
- }
5466
- else if (falseNode) {
5467
- return evaluateNode(falseNode, contextStack);
5468
- }
5469
- return null;
5904
+ return chain(evaluateNode(conditionNode, contextStack), (condition) => {
5905
+ if (condition) {
5906
+ return evaluateNode(trueNode, contextStack);
5907
+ }
5908
+ else if (falseNode) {
5909
+ return evaluateNode(falseNode, contextStack);
5910
+ }
5911
+ return null;
5912
+ });
5470
5913
  },
5471
5914
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => getUndefinedSymbols(node[1][1].filter(n => !!n), contextStack, builtin, evaluateNode),
5472
5915
  };
@@ -5497,13 +5940,15 @@ const unlessSpecialExpression = {
5497
5940
  docs: docs$9,
5498
5941
  evaluate: (node, contextStack, { evaluateNode }) => {
5499
5942
  const [conditionNode, trueNode, falseNode] = node[1][1];
5500
- if (!evaluateNode(conditionNode, contextStack)) {
5501
- return evaluateNode(trueNode, contextStack);
5502
- }
5503
- else if (falseNode) {
5504
- return evaluateNode(falseNode, contextStack);
5505
- }
5506
- return null;
5943
+ return chain(evaluateNode(conditionNode, contextStack), (condition) => {
5944
+ if (!condition) {
5945
+ return evaluateNode(trueNode, contextStack);
5946
+ }
5947
+ else if (falseNode) {
5948
+ return evaluateNode(falseNode, contextStack);
5949
+ }
5950
+ return null;
5951
+ });
5507
5952
  },
5508
5953
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => getUndefinedSymbols(node[1][1].filter(n => !!n), contextStack, builtin, evaluateNode),
5509
5954
  };
@@ -5529,10 +5974,12 @@ const letSpecialExpression = {
5529
5974
  const bindingNode = node[1][1];
5530
5975
  const target = bindingNode[1][0];
5531
5976
  const value = bindingNode[1][1];
5532
- const bindingValue = evaluateNode(value, contextStack);
5533
- const values = evaluateBindingNodeValues(target, bindingValue, Node => evaluateNode(Node, contextStack));
5534
- contextStack.addValues(values, target[2]);
5535
- return bindingValue;
5977
+ return chain(evaluateNode(value, contextStack), (bindingValue) => {
5978
+ return chain(evaluateBindingNodeValues(target, bindingValue, Node => evaluateNode(Node, contextStack)), (values) => {
5979
+ contextStack.addValues(values, target[2]);
5980
+ return bindingValue;
5981
+ });
5982
+ });
5536
5983
  },
5537
5984
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => {
5538
5985
  const bindingNode = node[1][1];
@@ -5579,39 +6026,93 @@ const loopSpecialExpression = {
5579
6026
  docs: docs$7,
5580
6027
  evaluate: (node, contextStack, { evaluateNode }) => {
5581
6028
  const bindingNodes = node[1][1];
5582
- const bindingContext = bindingNodes.reduce((result, bindingNode) => {
5583
- const val = evaluateNode(bindingNode[1][1], contextStack.create(result));
5584
- const valueRecord = evaluateBindingNodeValues(bindingNode[1][0], val, Node => evaluateNode(Node, contextStack));
5585
- Object.entries(valueRecord).forEach(([name, value]) => {
5586
- result[name] = { value };
6029
+ // Set up initial binding context sequentially (bindings may depend on each other)
6030
+ const initialContext = {};
6031
+ const setupBindings = reduceSequential(bindingNodes, (result, bindingNode) => {
6032
+ return chain(evaluateNode(bindingNode[1][1], contextStack.create(result)), (val) => {
6033
+ return chain(evaluateBindingNodeValues(bindingNode[1][0], val, Node => evaluateNode(Node, contextStack)), (valueRecord) => {
6034
+ Object.entries(valueRecord).forEach(([name, value]) => {
6035
+ result[name] = { value };
6036
+ });
6037
+ return result;
6038
+ });
5587
6039
  });
5588
- return result;
5589
- }, {});
5590
- const newContextStack = contextStack.create(bindingContext);
5591
- const body = node[1][2];
5592
- for (;;) {
5593
- let result = null;
5594
- try {
5595
- result = evaluateNode(body, newContextStack);
5596
- }
5597
- catch (error) {
5598
- if (error instanceof RecurSignal) {
5599
- const params = error.params;
5600
- if (params.length !== bindingNodes.length) {
5601
- throw new LitsError(`recur expected ${bindingNodes.length} parameters, got ${valueToString(params.length)}`, node[2]);
5602
- }
5603
- bindingNodes.forEach((bindingNode, index) => {
5604
- const valueRecord = evaluateBindingNodeValues(bindingNode[1][0], asAny(params[index]), Node => evaluateNode(Node, contextStack));
6040
+ }, initialContext);
6041
+ return chain(setupBindings, (bindingContext) => {
6042
+ const newContextStack = contextStack.create(bindingContext);
6043
+ const body = node[1][2];
6044
+ function rebindAndIterate(params) {
6045
+ if (params.length !== bindingNodes.length) {
6046
+ throw new LitsError(`recur expected ${bindingNodes.length} parameters, got ${valueToString(params.length)}`, node[2]);
6047
+ }
6048
+ return chain(forEachSequential(bindingNodes, (bindingNode, index) => {
6049
+ return chain(evaluateBindingNodeValues(bindingNode[1][0], asAny(params[index]), Node => evaluateNode(Node, contextStack)), (valueRecord) => {
5605
6050
  for (const [name, value] of Object.entries(valueRecord)) {
5606
6051
  bindingContext[name].value = value;
5607
6052
  }
5608
6053
  });
5609
- continue;
6054
+ }), () => iterate());
6055
+ }
6056
+ function iterate() {
6057
+ return tryCatch(() => evaluateNode(body, newContextStack), (error) => {
6058
+ if (error instanceof RecurSignal) {
6059
+ return rebindAndIterate(error.params);
6060
+ }
6061
+ throw error;
6062
+ });
6063
+ }
6064
+ // Use sync for(;;) loop for the sync case to avoid stack overflow
6065
+ for (;;) {
6066
+ try {
6067
+ const result = evaluateNode(body, newContextStack);
6068
+ if (result instanceof Promise) {
6069
+ // Async path: handle recur via promise chain
6070
+ return result.catch((error) => {
6071
+ if (error instanceof RecurSignal) {
6072
+ return rebindAndIterate(error.params);
6073
+ }
6074
+ throw error;
6075
+ });
6076
+ }
6077
+ return result;
6078
+ }
6079
+ catch (error) {
6080
+ if (error instanceof RecurSignal) {
6081
+ const params = error.params;
6082
+ if (params.length !== bindingNodes.length) {
6083
+ throw new LitsError(`recur expected ${bindingNodes.length} parameters, got ${valueToString(params.length)}`, node[2]);
6084
+ }
6085
+ // rebindAndIterate returns MaybePromise — if any binding default is async,
6086
+ // we must switch to the async iterate path
6087
+ for (let index = 0; index < bindingNodes.length; index += 1) {
6088
+ const bindingNode = bindingNodes[index];
6089
+ const valueRecord = evaluateBindingNodeValues(bindingNode[1][0], asAny(params[index]), Node => evaluateNode(Node, contextStack));
6090
+ if (valueRecord instanceof Promise) {
6091
+ // Switch to fully async path
6092
+ return valueRecord.then((resolved) => {
6093
+ for (const [name, value] of Object.entries(resolved)) {
6094
+ bindingContext[name].value = value;
6095
+ }
6096
+ // Handle remaining bindings then iterate
6097
+ return chain(forEachSequential(bindingNodes.slice(index + 1), (bn, subIndex) => {
6098
+ return chain(evaluateBindingNodeValues(bn[1][0], asAny(params[index + 1 + subIndex]), Node => evaluateNode(Node, contextStack)), (vr) => {
6099
+ for (const [name, value] of Object.entries(vr)) {
6100
+ bindingContext[name].value = value;
6101
+ }
6102
+ });
6103
+ }), () => iterate());
6104
+ });
6105
+ }
6106
+ for (const [name, value] of Object.entries(valueRecord)) {
6107
+ bindingContext[name].value = value;
6108
+ }
6109
+ }
6110
+ continue;
6111
+ }
6112
+ throw error;
5610
6113
  }
5611
- throw error;
5612
6114
  }
5613
- return result;
5614
- }
6115
+ });
5615
6116
  },
5616
6117
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => {
5617
6118
  const bindingNodes = node[1][1];
@@ -5631,74 +6132,107 @@ const loopSpecialExpression = {
5631
6132
  };
5632
6133
 
5633
6134
  function addToContext(bindings, context, contextStack, evaluateNode) {
6135
+ let bindingChain = undefined;
5634
6136
  for (const bindingNode of bindings) {
5635
- const [target, bindingValue] = bindingNode[1];
5636
- const val = evaluateNode(bindingValue, contextStack);
5637
- const valueRecord = evaluateBindingNodeValues(target, val, Node => evaluateNode(Node, contextStack));
5638
- Object.entries(valueRecord).forEach(([name, value]) => {
5639
- context[name] = { value };
6137
+ bindingChain = chain(bindingChain, () => {
6138
+ const [target, bindingValue] = bindingNode[1];
6139
+ return chain(evaluateNode(bindingValue, contextStack), (val) => {
6140
+ return chain(evaluateBindingNodeValues(target, val, Node => evaluateNode(Node, contextStack)), (valueRecord) => {
6141
+ Object.entries(valueRecord).forEach(([name, value]) => {
6142
+ context[name] = { value };
6143
+ });
6144
+ });
6145
+ });
5640
6146
  });
5641
6147
  }
6148
+ return bindingChain;
5642
6149
  }
5643
6150
  function evaluateLoop(returnResult, loopNode, contextStack, evaluateNode) {
5644
6151
  const sourceCodeInfo = loopNode[2];
5645
6152
  const [, loopBindings, body] = loopNode[1];
5646
6153
  const result = [];
5647
6154
  const bindingIndices = loopBindings.map(() => 0);
5648
- let abort = false;
5649
- while (!abort) {
6155
+ function processIteration() {
5650
6156
  const context = {};
5651
6157
  const newContextStack = contextStack.create(context);
5652
- let skip = false;
5653
- bindingsLoop: for (let bindingIndex = 0; bindingIndex < loopBindings.length; bindingIndex += 1) {
6158
+ function processBinding(bindingIndex) {
6159
+ if (bindingIndex >= loopBindings.length)
6160
+ return 'continue';
5654
6161
  const [bindingNode, letBindings, whenNode, whileNode] = loopBindings[bindingIndex];
5655
6162
  const [targetNode, valueNode] = bindingNode[1];
5656
- const coll = asColl(evaluateNode(valueNode, newContextStack), sourceCodeInfo);
5657
- const seq = isSeq(coll) ? coll : Object.entries(coll);
5658
- if (seq.length === 0) {
5659
- skip = true;
5660
- abort = true;
5661
- break;
5662
- }
5663
- const index = asNonUndefined(bindingIndices[bindingIndex], sourceCodeInfo);
5664
- if (index >= seq.length) {
5665
- skip = true;
5666
- if (bindingIndex === 0) {
5667
- abort = true;
5668
- break;
6163
+ return chain(evaluateNode(valueNode, newContextStack), (rawColl) => {
6164
+ const coll = asColl(rawColl, sourceCodeInfo);
6165
+ const seq = isSeq(coll) ? coll : Object.entries(coll);
6166
+ if (seq.length === 0) {
6167
+ return 'abort';
5669
6168
  }
5670
- bindingIndices[bindingIndex] = 0;
5671
- bindingIndices[bindingIndex - 1] = asNonUndefined(bindingIndices[bindingIndex - 1], sourceCodeInfo) + 1;
5672
- break;
5673
- }
5674
- const val = asAny(seq[index], sourceCodeInfo);
5675
- const valueRecord = evaluateBindingNodeValues(targetNode, val, Node => evaluateNode(Node, newContextStack));
5676
- Object.entries(valueRecord).forEach(([name, value]) => {
5677
- context[name] = { value };
6169
+ const index = asNonUndefined(bindingIndices[bindingIndex], sourceCodeInfo);
6170
+ if (index >= seq.length) {
6171
+ if (bindingIndex === 0) {
6172
+ return 'abort';
6173
+ }
6174
+ bindingIndices[bindingIndex] = 0;
6175
+ bindingIndices[bindingIndex - 1] = asNonUndefined(bindingIndices[bindingIndex - 1], sourceCodeInfo) + 1;
6176
+ return 'skip';
6177
+ }
6178
+ const val = asAny(seq[index], sourceCodeInfo);
6179
+ return chain(evaluateBindingNodeValues(targetNode, val, Node => evaluateNode(Node, newContextStack)), (valueRecord) => {
6180
+ Object.entries(valueRecord).forEach(([name, value]) => {
6181
+ context[name] = { value };
6182
+ });
6183
+ return chain(letBindings.length > 0
6184
+ ? addToContext(letBindings, context, newContextStack, evaluateNode)
6185
+ : undefined, () => {
6186
+ if (whenNode) {
6187
+ return chain(evaluateNode(whenNode, newContextStack), (whenResult) => {
6188
+ if (!whenResult) {
6189
+ bindingIndices[bindingIndex] = asNonUndefined(bindingIndices[bindingIndex], sourceCodeInfo) + 1;
6190
+ return 'skip';
6191
+ }
6192
+ if (whileNode) {
6193
+ return chain(evaluateNode(whileNode, newContextStack), (whileResult) => {
6194
+ if (!whileResult) {
6195
+ bindingIndices[bindingIndex] = Number.POSITIVE_INFINITY;
6196
+ return 'skip';
6197
+ }
6198
+ return processBinding(bindingIndex + 1);
6199
+ });
6200
+ }
6201
+ return processBinding(bindingIndex + 1);
6202
+ });
6203
+ }
6204
+ if (whileNode) {
6205
+ return chain(evaluateNode(whileNode, newContextStack), (whileResult) => {
6206
+ if (!whileResult) {
6207
+ bindingIndices[bindingIndex] = Number.POSITIVE_INFINITY;
6208
+ return 'skip';
6209
+ }
6210
+ return processBinding(bindingIndex + 1);
6211
+ });
6212
+ }
6213
+ return processBinding(bindingIndex + 1);
6214
+ });
6215
+ });
5678
6216
  });
5679
- if (letBindings) {
5680
- addToContext(letBindings, context, newContextStack, evaluateNode);
5681
- }
5682
- if (whenNode && !evaluateNode(whenNode, newContextStack)) {
5683
- bindingIndices[bindingIndex] = asNonUndefined(bindingIndices[bindingIndex], sourceCodeInfo) + 1;
5684
- skip = true;
5685
- break bindingsLoop;
6217
+ }
6218
+ return chain(processBinding(0), (status) => {
6219
+ if (status === 'abort') {
6220
+ return returnResult ? result : null;
5686
6221
  }
5687
- if (whileNode && !evaluateNode(whileNode, newContextStack)) {
5688
- bindingIndices[bindingIndex] = Number.POSITIVE_INFINITY;
5689
- skip = true;
5690
- break bindingsLoop;
6222
+ if (status === 'skip') {
6223
+ return processIteration();
5691
6224
  }
5692
- }
5693
- if (!skip) {
5694
- const value = evaluateNode(body, newContextStack);
5695
- if (returnResult)
5696
- result.push(value);
5697
- if (bindingIndices.length > 0)
5698
- bindingIndices[bindingIndices.length - 1] += 1;
5699
- }
6225
+ // status === 'continue'
6226
+ return chain(evaluateNode(body, newContextStack), (value) => {
6227
+ if (returnResult)
6228
+ result.push(value);
6229
+ if (bindingIndices.length > 0)
6230
+ bindingIndices[bindingIndices.length - 1] += 1;
6231
+ return processIteration();
6232
+ });
6233
+ });
5700
6234
  }
5701
- return returnResult ? result : null;
6235
+ return processIteration();
5702
6236
  }
5703
6237
  function analyze(loopNode, contextStack, getUndefinedSymbols, builtin, evaluateNode) {
5704
6238
  const result = new Set();
@@ -5787,8 +6321,7 @@ const doseqSpecialExpression = {
5787
6321
  arity: toFixedArity(1),
5788
6322
  docs: doseqDocs,
5789
6323
  evaluate: (node, contextStack, helpers) => {
5790
- evaluateLoop(false, node, contextStack, helpers.evaluateNode);
5791
- return null;
6324
+ return chain(evaluateLoop(false, node, contextStack, helpers.evaluateNode), () => null);
5792
6325
  },
5793
6326
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => analyze(node, contextStack, getUndefinedSymbols, builtin, evaluateNode),
5794
6327
  };
@@ -5828,13 +6361,11 @@ const orSpecialExpression = {
5828
6361
  arity: {},
5829
6362
  docs: docs$6,
5830
6363
  evaluate: (node, contextStack, { evaluateNode }) => {
5831
- let value = false;
5832
- for (const param of node[1][1]) {
5833
- value = evaluateNode(param, contextStack);
5834
- if (value)
5835
- break;
5836
- }
5837
- return value;
6364
+ return reduceSequential(node[1][1], (acc, param) => {
6365
+ if (acc)
6366
+ return acc;
6367
+ return evaluateNode(param, contextStack);
6368
+ }, false);
5838
6369
  },
5839
6370
  evaluateAsNormalExpression: (params, sourceCodeInfo) => {
5840
6371
  let value = false;
@@ -5887,16 +6418,21 @@ const qqSpecialExpression = {
5887
6418
  arity: { min: 1 },
5888
6419
  docs: docs$5,
5889
6420
  evaluate: (node, contextStack, { evaluateNode }) => {
5890
- for (const param of node[1][1]) {
6421
+ // Use a sentinel to know we haven't found a non-null value yet
6422
+ const SENTINEL = Symbol('qq-sentinel');
6423
+ return chain(reduceSequential(node[1][1], (acc, param) => {
6424
+ if (acc !== SENTINEL)
6425
+ return acc;
5891
6426
  if (isUserDefinedSymbolNode(param) && contextStack.lookUp(param) === null) {
5892
- continue;
5893
- }
5894
- const result = evaluateNode(param, contextStack);
5895
- if (result !== null) {
5896
- return result;
6427
+ return SENTINEL;
5897
6428
  }
5898
- }
5899
- return null;
6429
+ return chain(evaluateNode(param, contextStack), (result) => {
6430
+ if (result !== null) {
6431
+ return result;
6432
+ }
6433
+ return SENTINEL;
6434
+ });
6435
+ }, SENTINEL), result => result === SENTINEL ? null : result);
5900
6436
  },
5901
6437
  evaluateAsNormalExpression: (params, sourceCodeInfo) => {
5902
6438
  for (const param of params) {
@@ -5918,7 +6454,7 @@ const docs$4 = {
5918
6454
  `
5919
6455
  let foo = (n) -> do
5920
6456
  write!(n);
5921
- if !(zero?(n)) then
6457
+ if not(zero?(n)) then
5922
6458
  recur(n - 1)
5923
6459
  end
5924
6460
  end;
@@ -5926,14 +6462,14 @@ foo(3)`,
5926
6462
  `
5927
6463
  (n -> do
5928
6464
  write!(n);
5929
- if !(zero?(n)) then
6465
+ if not(zero?(n)) then
5930
6466
  recur(n - 1)
5931
6467
  end
5932
6468
  end)(3)`,
5933
6469
  `
5934
6470
  loop (n = 3) -> do
5935
6471
  write!(n);
5936
- if !(zero?(n)) then
6472
+ if not(zero?(n)) then
5937
6473
  recur(n - 1)
5938
6474
  end
5939
6475
  end`,
@@ -5944,8 +6480,9 @@ const recurSpecialExpression = {
5944
6480
  docs: docs$4,
5945
6481
  evaluate: (node, contextStack, { evaluateNode }) => {
5946
6482
  const params = node[1][1];
5947
- const evaluatedParams = params.map(paramNode => evaluateNode(paramNode, contextStack));
5948
- throw new RecurSignal(evaluatedParams);
6483
+ return chain(mapSequential(params, paramNode => evaluateNode(paramNode, contextStack)), (evaluatedParams) => {
6484
+ throw new RecurSignal(evaluatedParams);
6485
+ });
5949
6486
  },
5950
6487
  evaluateAsNormalExpression: (params) => {
5951
6488
  throw new RecurSignal(params);
@@ -5976,10 +6513,12 @@ const throwSpecialExpression = {
5976
6513
  arity: toFixedArity(1),
5977
6514
  docs: docs$3,
5978
6515
  evaluate: (node, contextStack, { evaluateNode }) => {
5979
- const message = asString(evaluateNode(node[1][1], contextStack), node[2], {
5980
- nonEmpty: true,
6516
+ return chain(evaluateNode(node[1][1], contextStack), (result) => {
6517
+ const message = asString(result, node[2], {
6518
+ nonEmpty: true,
6519
+ });
6520
+ throw new UserDefinedError(message, node[2]);
5981
6521
  });
5982
- throw new UserDefinedError(message, node[2]);
5983
6522
  },
5984
6523
  evaluateAsNormalExpression: (params, sourceCodeInfo) => {
5985
6524
  const message = asString(params[0], sourceCodeInfo, {
@@ -6025,17 +6564,14 @@ const trySpecialExpression = {
6025
6564
  docs: docs$2,
6026
6565
  evaluate: (node, contextStack, { evaluateNode }) => {
6027
6566
  const [, tryExpression, errorSymbol, catchExpression] = node[1];
6028
- try {
6029
- return evaluateNode(tryExpression, contextStack);
6030
- }
6031
- catch (error) {
6567
+ return tryCatch(() => evaluateNode(tryExpression, contextStack), (error) => {
6032
6568
  const newContext = errorSymbol
6033
6569
  ? {
6034
6570
  [errorSymbol[1]]: { value: error },
6035
6571
  }
6036
6572
  : {};
6037
6573
  return evaluateNode(catchExpression, contextStack.create(newContext));
6038
- }
6574
+ });
6039
6575
  },
6040
6576
  getUndefinedSymbols: (node, contextStack, { getUndefinedSymbols, builtin, evaluateNode }) => {
6041
6577
  const [, tryExpression, errorSymbol, catchExpression] = node[1];
@@ -6082,19 +6618,21 @@ const arraySpecialExpression = {
6082
6618
  docs: docs$1,
6083
6619
  evaluate: (node, contextStack, { evaluateNode }) => {
6084
6620
  const result = [];
6085
- for (const param of node[1][1]) {
6621
+ return chain(forEachSequential(node[1][1], (param) => {
6086
6622
  if (isSpreadNode(param)) {
6087
- const spreadValue = evaluateNode(param[1], contextStack);
6088
- if (!Array.isArray(spreadValue)) {
6089
- throw new LitsError('Spread value is not an array', param[2]);
6090
- }
6091
- result.push(...spreadValue);
6623
+ return chain(evaluateNode(param[1], contextStack), (spreadValue) => {
6624
+ if (!Array.isArray(spreadValue)) {
6625
+ throw new LitsError('Spread value is not an array', param[2]);
6626
+ }
6627
+ result.push(...spreadValue);
6628
+ });
6092
6629
  }
6093
6630
  else {
6094
- result.push(evaluateNode(param, contextStack));
6631
+ return chain(evaluateNode(param, contextStack), (value) => {
6632
+ result.push(value);
6633
+ });
6095
6634
  }
6096
- }
6097
- return result;
6635
+ }), () => result);
6098
6636
  },
6099
6637
  evaluateAsNormalExpression: (params, sourceCodeInfo) => {
6100
6638
  const result = [];
@@ -6147,28 +6685,34 @@ const objectSpecialExpression = {
6147
6685
  evaluate: (node, contextStack, { evaluateNode }) => {
6148
6686
  const result = {};
6149
6687
  const params = node[1][1];
6150
- for (let i = 0; i < params.length; i += 2) {
6688
+ function processEntry(i) {
6689
+ if (i >= params.length)
6690
+ return result;
6151
6691
  const keyNode = params[i];
6152
6692
  if (isSpreadNode(keyNode)) {
6153
- const spreadObject = evaluateNode(keyNode[1], contextStack);
6154
- if (!isUnknownRecord(spreadObject)) {
6155
- throw new LitsError('Spread value is not an object', keyNode[2]);
6156
- }
6157
- Object.assign(result, spreadObject);
6158
- i -= 1;
6693
+ return chain(evaluateNode(keyNode[1], contextStack), (spreadObject) => {
6694
+ if (!isUnknownRecord(spreadObject)) {
6695
+ throw new LitsError('Spread value is not an object', keyNode[2]);
6696
+ }
6697
+ Object.assign(result, spreadObject);
6698
+ return processEntry(i + 1);
6699
+ });
6159
6700
  }
6160
6701
  else {
6161
- const key = evaluateNode(keyNode, contextStack);
6162
6702
  const valueNode = params[i + 1];
6163
6703
  if (valueNode === undefined) {
6164
6704
  throw new LitsError('Missing value for key', keyNode[2]);
6165
6705
  }
6166
- const value = evaluateNode(valueNode, contextStack);
6167
- assertString(key, keyNode[2]);
6168
- result[key] = value;
6706
+ return chain(evaluateNode(keyNode, contextStack), (key) => {
6707
+ return chain(evaluateNode(valueNode, contextStack), (value) => {
6708
+ assertString(key, keyNode[2]);
6709
+ result[key] = value;
6710
+ return processEntry(i + 2);
6711
+ });
6712
+ });
6169
6713
  }
6170
6714
  }
6171
- return result;
6715
+ return processEntry(0);
6172
6716
  },
6173
6717
  evaluateAsNormalExpression: (params, sourceCodeInfo) => {
6174
6718
  const result = {};
@@ -6267,7 +6811,19 @@ function isNumberReservedSymbol(symbol) {
6267
6811
  const functionExecutors = {
6268
6812
  NativeJsFunction: (fn, params, sourceCodeInfo) => {
6269
6813
  try {
6270
- return toAny(fn.nativeFn.fn(...params));
6814
+ const result = fn.nativeFn.fn(...params);
6815
+ // If the native function returns a Promise, await it transparently
6816
+ if (result instanceof Promise) {
6817
+ return result.then(resolved => toAny(resolved), (error) => {
6818
+ const message = typeof error === 'string'
6819
+ ? error
6820
+ : isUnknownRecord(error) && typeof error.message === 'string'
6821
+ ? error.message
6822
+ : '<no message>';
6823
+ throw new LitsError(`Native function threw: "${message}"`, sourceCodeInfo);
6824
+ });
6825
+ }
6826
+ return toAny(result);
6271
6827
  }
6272
6828
  catch (error) {
6273
6829
  const message = typeof error === 'string'
@@ -6279,9 +6835,9 @@ const functionExecutors = {
6279
6835
  }
6280
6836
  },
6281
6837
  UserDefined: (fn, params, sourceCodeInfo, contextStack, { evaluateNode }) => {
6282
- for (;;) {
6283
- if (!arityAcceptsMin(fn.arity, params.length)) {
6284
- throw new LitsError(`Expected ${fn.arity} arguments, got ${params.length}.`, sourceCodeInfo);
6838
+ function setupAndExecute(currentParams) {
6839
+ if (!arityAcceptsMin(fn.arity, currentParams.length)) {
6840
+ throw new LitsError(`Expected ${fn.arity} arguments, got ${currentParams.length}.`, sourceCodeInfo);
6285
6841
  }
6286
6842
  const evaluatedFunction = fn.evaluatedfunction;
6287
6843
  const args = evaluatedFunction[0];
@@ -6289,39 +6845,70 @@ const functionExecutors = {
6289
6845
  const newContextStack = contextStack.create(fn.evaluatedfunction[2]);
6290
6846
  const newContext = { self: { value: fn } };
6291
6847
  const rest = [];
6292
- for (let i = 0; i < params.length; i += 1) {
6848
+ // Process non-rest params sequentially since binding evaluation may be async
6849
+ let paramSetup = undefined;
6850
+ for (let i = 0; i < currentParams.length; i += 1) {
6293
6851
  if (i < nbrOfNonRestArgs) {
6294
- const param = toAny(params[i]);
6295
- const valueRecord = evaluateBindingNodeValues(args[i], param, node => evaluateNode(node, newContextStack.create(newContext)));
6296
- Object.entries(valueRecord).forEach(([key, value]) => {
6297
- newContext[key] = { value };
6852
+ const paramIndex = i;
6853
+ paramSetup = chain(paramSetup, () => {
6854
+ const param = toAny(currentParams[paramIndex]);
6855
+ return chain(evaluateBindingNodeValues(args[paramIndex], param, node => evaluateNode(node, newContextStack.create(newContext))), (valueRecord) => {
6856
+ Object.entries(valueRecord).forEach(([key, value]) => {
6857
+ newContext[key] = { value };
6858
+ });
6859
+ });
6298
6860
  });
6299
6861
  }
6300
6862
  else {
6301
- rest.push(toAny(params[i]));
6863
+ rest.push(toAny(currentParams[i]));
6302
6864
  }
6303
6865
  }
6304
- for (let i = params.length; i < nbrOfNonRestArgs; i++) {
6305
- const arg = args[i];
6306
- const defaultValue = evaluateNode(arg[1][1], contextStack.create(newContext));
6307
- const valueRecord = evaluateBindingNodeValues(arg, defaultValue, node => evaluateNode(node, contextStack.create(newContext)));
6308
- Object.entries(valueRecord).forEach(([key, value]) => {
6309
- newContext[key] = { value };
6866
+ // Handle default values for optional params chain sequentially since they may be async
6867
+ let defaultSetup = undefined;
6868
+ for (let i = currentParams.length; i < nbrOfNonRestArgs; i++) {
6869
+ const argIndex = i;
6870
+ defaultSetup = chain(defaultSetup, () => {
6871
+ const arg = args[argIndex];
6872
+ return chain(evaluateNode(arg[1][1], contextStack.create(newContext)), (defaultValue) => {
6873
+ return chain(evaluateBindingNodeValues(arg, defaultValue, node => evaluateNode(node, contextStack.create(newContext))), (valueRecord) => {
6874
+ Object.entries(valueRecord).forEach(([key, value]) => {
6875
+ newContext[key] = { value };
6876
+ });
6877
+ });
6878
+ });
6310
6879
  });
6311
6880
  }
6312
- const restArgument = args.find(arg => arg[0] === bindingTargetTypes.rest);
6313
- if (restArgument !== undefined) {
6314
- const valueRecord = evaluateBindingNodeValues(restArgument, rest, node => evaluateNode(node, contextStack.create(newContext)));
6315
- Object.entries(valueRecord).forEach(([key, value]) => {
6316
- newContext[key] = { value };
6881
+ return chain(paramSetup, () => chain(defaultSetup, () => {
6882
+ const restArgument = args.find(arg => arg[0] === bindingTargetTypes.rest);
6883
+ const restSetup = restArgument !== undefined
6884
+ ? chain(evaluateBindingNodeValues(restArgument, rest, node => evaluateNode(node, contextStack.create(newContext))), (valueRecord) => {
6885
+ Object.entries(valueRecord).forEach(([key, value]) => {
6886
+ newContext[key] = { value };
6887
+ });
6888
+ })
6889
+ : undefined;
6890
+ return chain(restSetup, () => {
6891
+ // Evaluate body nodes sequentially
6892
+ const newContextStack2 = newContextStack.create(newContext);
6893
+ const bodyResult = reduceSequential(evaluatedFunction[1], (_acc, node) => evaluateNode(node, newContextStack2), null);
6894
+ // Handle RecurSignal for async body results
6895
+ if (bodyResult instanceof Promise) {
6896
+ return bodyResult.catch((error) => {
6897
+ if (error instanceof RecurSignal) {
6898
+ return setupAndExecute(error.params);
6899
+ }
6900
+ throw error;
6901
+ });
6902
+ }
6903
+ return bodyResult;
6317
6904
  });
6318
- }
6905
+ }));
6906
+ }
6907
+ // Sync recur loop: use for(;;) to avoid stack overflow for sync tail recursion
6908
+ for (;;) {
6319
6909
  try {
6320
- let result = null;
6321
- const newContextStack2 = newContextStack.create(newContext);
6322
- for (const node of evaluatedFunction[1]) {
6323
- result = evaluateNode(node, newContextStack2);
6324
- }
6910
+ const result = setupAndExecute(params);
6911
+ // If result is async, the RecurSignal handling is inside the Promise chain
6325
6912
  return result;
6326
6913
  }
6327
6914
  catch (error) {
@@ -6351,38 +6938,51 @@ const functionExecutors = {
6351
6938
  throw new LitsError(`(comp) expects one argument, got ${valueToString(params.length)}.`, sourceCodeInfo);
6352
6939
  return asAny(params[0], sourceCodeInfo);
6353
6940
  }
6354
- return asAny(f.reduceRight((result, fun) => {
6355
- return [executeFunction(asFunctionLike(fun, sourceCodeInfo), result, contextStack, sourceCodeInfo)];
6356
- }, params)[0], sourceCodeInfo);
6941
+ // reduceRight with MaybePromise: each step wraps result in array, passes to next function
6942
+ let result = params;
6943
+ for (let i = f.length - 1; i >= 0; i--) {
6944
+ const fun = f[i];
6945
+ result = chain(result, (currentParams) => {
6946
+ return chain(executeFunction(asFunctionLike(fun, sourceCodeInfo), currentParams, contextStack, sourceCodeInfo), r => [r]);
6947
+ });
6948
+ }
6949
+ return chain(result, finalArr => asAny(finalArr[0], sourceCodeInfo));
6357
6950
  },
6358
6951
  Constantly: (fn) => {
6359
6952
  return fn.value;
6360
6953
  },
6361
6954
  Juxt: (fn, params, sourceCodeInfo, contextStack, { executeFunction }) => {
6362
- return fn.params.map(fun => executeFunction(asFunctionLike(fun, sourceCodeInfo), params, contextStack, sourceCodeInfo));
6955
+ return mapSequential(fn.params, fun => executeFunction(asFunctionLike(fun, sourceCodeInfo), params, contextStack, sourceCodeInfo));
6363
6956
  },
6364
6957
  Complement: (fn, params, sourceCodeInfo, contextStack, { executeFunction }) => {
6365
- return !executeFunction(fn.function, params, contextStack, sourceCodeInfo);
6958
+ return chain(executeFunction(fn.function, params, contextStack, sourceCodeInfo), result => !result);
6366
6959
  },
6367
6960
  EveryPred: (fn, params, sourceCodeInfo, contextStack, { executeFunction }) => {
6961
+ // Flatten to sequential checks: for each predicate, for each param
6962
+ const checks = [];
6368
6963
  for (const f of fn.params) {
6369
6964
  for (const param of params) {
6370
- const result = executeFunction(asFunctionLike(f, sourceCodeInfo), [param], contextStack, sourceCodeInfo);
6371
- if (!result)
6372
- return false;
6965
+ checks.push(() => executeFunction(asFunctionLike(f, sourceCodeInfo), [param], contextStack, sourceCodeInfo));
6373
6966
  }
6374
6967
  }
6375
- return true;
6968
+ return reduceSequential(checks, (acc, check) => {
6969
+ if (!acc)
6970
+ return false;
6971
+ return chain(check(), result => !!result);
6972
+ }, true);
6376
6973
  },
6377
6974
  SomePred: (fn, params, sourceCodeInfo, contextStack, { executeFunction }) => {
6975
+ const checks = [];
6378
6976
  for (const f of fn.params) {
6379
6977
  for (const param of params) {
6380
- const result = executeFunction(asFunctionLike(f, sourceCodeInfo), [param], contextStack, sourceCodeInfo);
6381
- if (result)
6382
- return true;
6978
+ checks.push(() => executeFunction(asFunctionLike(f, sourceCodeInfo), [param], contextStack, sourceCodeInfo));
6383
6979
  }
6384
6980
  }
6385
- return false;
6981
+ return reduceSequential(checks, (acc, check) => {
6982
+ if (acc)
6983
+ return true;
6984
+ return chain(check(), result => !!result);
6985
+ }, false);
6386
6986
  },
6387
6987
  Fnull: (fn, params, sourceCodeInfo, contextStack, { executeFunction }) => {
6388
6988
  const fnulledParams = params.map((param, index) => (param === null ? toAny(fn.params[index]) : param));
@@ -6416,11 +7016,7 @@ const functionExecutors = {
6416
7016
  };
6417
7017
 
6418
7018
  function evaluate(ast, contextStack) {
6419
- let result = null;
6420
- for (const node of ast.body) {
6421
- result = evaluateNode(node, contextStack);
6422
- }
6423
- return result;
7019
+ return reduceSequential(ast.body, (_acc, node) => evaluateNode(node, contextStack), null);
6424
7020
  }
6425
7021
  function evaluateNode(node, contextStack) {
6426
7022
  switch (node[0]) {
@@ -6436,13 +7032,15 @@ function evaluateNode(node, contextStack) {
6436
7032
  return evaluateReservedSymbol(node);
6437
7033
  case NodeTypes.NormalExpression: {
6438
7034
  const result = evaluateNormalExpression(node, contextStack);
6439
- if (typeof result === 'number' && Number.isNaN(result)) {
6440
- throw new LitsError('Number is NaN', node[2]);
6441
- }
6442
- return annotate(result);
7035
+ return chain(result, (resolved) => {
7036
+ if (typeof resolved === 'number' && Number.isNaN(resolved)) {
7037
+ throw new LitsError('Number is NaN', node[2]);
7038
+ }
7039
+ return annotate(resolved);
7040
+ });
6443
7041
  }
6444
7042
  case NodeTypes.SpecialExpression:
6445
- return annotate(evaluateSpecialExpression(node, contextStack));
7043
+ return chain(evaluateSpecialExpression(node, contextStack), resolved => annotate(resolved));
6446
7044
  /* v8 ignore next 2 */
6447
7045
  default:
6448
7046
  throw new LitsError(`${getNodeTypeName(node[0])}-node cannot be evaluated`, node[2]);
@@ -6462,73 +7060,84 @@ function evaluateReservedSymbol(node) {
6462
7060
  const value = reservedSymbolRecord[reservedName];
6463
7061
  return asNonUndefined(value, node[2]);
6464
7062
  }
6465
- function evaluateNormalExpression(node, contextStack) {
6466
- const sourceCodeInfo = node[2];
6467
- const paramNodes = node[1][1];
7063
+ function evaluateParams(paramNodes, contextStack) {
6468
7064
  const params = [];
6469
7065
  const placeholders = [];
6470
- paramNodes.forEach((paramNode, index) => {
7066
+ const result = forEachSequential(paramNodes, (paramNode, index) => {
6471
7067
  if (isSpreadNode(paramNode)) {
6472
- const spreadValue = evaluateNode(paramNode[1], contextStack);
6473
- if (Array.isArray(spreadValue)) {
6474
- params.push(...spreadValue);
6475
- }
6476
- else {
6477
- throw new LitsError(`Spread operator requires an array, got ${valueToString(paramNode)}`, paramNode[2]);
6478
- }
7068
+ return chain(evaluateNode(paramNode[1], contextStack), (spreadValue) => {
7069
+ if (Array.isArray(spreadValue)) {
7070
+ params.push(...spreadValue);
7071
+ }
7072
+ else {
7073
+ throw new LitsError(`Spread operator requires an array, got ${valueToString(paramNode)}`, paramNode[2]);
7074
+ }
7075
+ });
6479
7076
  }
6480
7077
  else if (paramNode[0] === NodeTypes.ReservedSymbol && paramNode[1] === '_') {
6481
7078
  placeholders.push(index);
6482
7079
  }
6483
7080
  else {
6484
- params.push(evaluateNode(paramNode, contextStack));
7081
+ return chain(evaluateNode(paramNode, contextStack), (value) => {
7082
+ params.push(value);
7083
+ });
6485
7084
  }
6486
7085
  });
6487
- if (isNormalExpressionNodeWithName(node)) {
6488
- const nameSymbol = node[1][0];
6489
- if (placeholders.length > 0) {
6490
- const fn = evaluateNode(nameSymbol, contextStack);
6491
- const partialFunction = {
6492
- [FUNCTION_SYMBOL]: true,
6493
- function: asFunctionLike(fn, sourceCodeInfo),
6494
- functionType: 'Partial',
6495
- params,
6496
- placeholders,
6497
- sourceCodeInfo,
6498
- arity: toFixedArity(placeholders.length),
6499
- };
6500
- return partialFunction;
6501
- }
6502
- if (isNormalBuiltinSymbolNode(nameSymbol)) {
6503
- const type = nameSymbol[1];
6504
- const normalExpression = builtin.allNormalExpressions[type];
6505
- return normalExpression.evaluate(params, node[2], contextStack, { executeFunction });
6506
- }
6507
- else {
6508
- const fn = contextStack.getValue(nameSymbol[1]);
6509
- if (fn !== undefined) {
6510
- return executeFunction(asFunctionLike(fn, sourceCodeInfo), params, contextStack, sourceCodeInfo);
7086
+ return chain(result, () => ({ params, placeholders }));
7087
+ }
7088
+ function evaluateNormalExpression(node, contextStack) {
7089
+ const sourceCodeInfo = node[2];
7090
+ return chain(evaluateParams(node[1][1], contextStack), ({ params, placeholders }) => {
7091
+ if (isNormalExpressionNodeWithName(node)) {
7092
+ const nameSymbol = node[1][0];
7093
+ if (placeholders.length > 0) {
7094
+ const fn = evaluateNode(nameSymbol, contextStack);
7095
+ return chain(fn, (resolvedFn) => {
7096
+ const partialFunction = {
7097
+ [FUNCTION_SYMBOL]: true,
7098
+ function: asFunctionLike(resolvedFn, sourceCodeInfo),
7099
+ functionType: 'Partial',
7100
+ params,
7101
+ placeholders,
7102
+ sourceCodeInfo,
7103
+ arity: toFixedArity(placeholders.length),
7104
+ };
7105
+ return partialFunction;
7106
+ });
7107
+ }
7108
+ if (isNormalBuiltinSymbolNode(nameSymbol)) {
7109
+ const type = nameSymbol[1];
7110
+ const normalExpression = builtin.allNormalExpressions[type];
7111
+ return normalExpression.evaluate(params, node[2], contextStack, { executeFunction });
7112
+ }
7113
+ else {
7114
+ const fn = contextStack.getValue(nameSymbol[1]);
7115
+ if (fn !== undefined) {
7116
+ return executeFunction(asFunctionLike(fn, sourceCodeInfo), params, contextStack, sourceCodeInfo);
7117
+ }
7118
+ throw new UndefinedSymbolError(nameSymbol[1], node[2]);
6511
7119
  }
6512
- throw new UndefinedSymbolError(nameSymbol[1], node[2]);
6513
7120
  }
6514
- }
6515
- else {
6516
- const fnNode = node[1][0];
6517
- const fn = asFunctionLike(evaluateNode(fnNode, contextStack), sourceCodeInfo);
6518
- if (placeholders.length > 0) {
6519
- const partialFunction = {
6520
- [FUNCTION_SYMBOL]: true,
6521
- function: fn,
6522
- functionType: 'Partial',
6523
- params,
6524
- placeholders,
6525
- sourceCodeInfo,
6526
- arity: toFixedArity(placeholders.length),
6527
- };
6528
- return partialFunction;
7121
+ else {
7122
+ const fnNode = node[1][0];
7123
+ return chain(evaluateNode(fnNode, contextStack), (resolvedFn) => {
7124
+ const fn = asFunctionLike(resolvedFn, sourceCodeInfo);
7125
+ if (placeholders.length > 0) {
7126
+ const partialFunction = {
7127
+ [FUNCTION_SYMBOL]: true,
7128
+ function: fn,
7129
+ functionType: 'Partial',
7130
+ params,
7131
+ placeholders,
7132
+ sourceCodeInfo,
7133
+ arity: toFixedArity(placeholders.length),
7134
+ };
7135
+ return partialFunction;
7136
+ }
7137
+ return executeFunction(fn, params, contextStack, sourceCodeInfo);
7138
+ });
6529
7139
  }
6530
- return executeFunction(fn, params, contextStack, sourceCodeInfo);
6531
- }
7140
+ });
6532
7141
  }
6533
7142
  function executeFunction(fn, params, contextStack, sourceCodeInfo) {
6534
7143
  if (isLitsFunction(fn))
@@ -6804,7 +7413,7 @@ const binaryOperators = [
6804
7413
  '≥', // greater than or equal
6805
7414
  '==', // equal
6806
7415
  '!=', // not equal
6807
- '', // not equal
7416
+ '!=', // not equal
6808
7417
  '&', // bitwise AND
6809
7418
  'xor', // bitwise XOR
6810
7419
  '|', // bitwise OR
@@ -7587,6 +8196,7 @@ class ParserContext {
7587
8196
  const token = this.tokens[this.position];
7588
8197
  if (!token) {
7589
8198
  const lastToken = this.tokens.at(-1);
8199
+ /* v8 ignore next */
7590
8200
  const sourceCodeInfo = lastToken ? lastToken[2] : undefined;
7591
8201
  throw new LitsError('Unexpected end of input', sourceCodeInfo);
7592
8202
  }
@@ -7713,7 +8323,6 @@ function fromBinaryOperatorToNode(operator, symbolNode, left, right, sourceCodeI
7713
8323
  case '≥':
7714
8324
  case '==':
7715
8325
  case '!=':
7716
- case '≠':
7717
8326
  case '&':
7718
8327
  case 'xor':
7719
8328
  case '|':
@@ -8637,7 +9246,6 @@ function getPrecedence(operatorSign, sourceCodeInfo) {
8637
9246
  return 7;
8638
9247
  case '==': // equal
8639
9248
  case '!=': // not equal
8640
- case '≠': // not equal
8641
9249
  return 6;
8642
9250
  case '&': // bitwise AND
8643
9251
  case 'xor': // bitwise XOR
@@ -8863,15 +9471,36 @@ class Lits {
8863
9471
  debug: this.debug,
8864
9472
  };
8865
9473
  }
9474
+ async = {
9475
+ run: async (program, params = {}) => {
9476
+ const ast = this.generateAst(program, params);
9477
+ return this.evaluate(ast, params);
9478
+ },
9479
+ context: async (programOrAst, params = {}) => {
9480
+ const ast = typeof programOrAst === 'string' ? this.generateAst(programOrAst, params) : programOrAst;
9481
+ const contextStack = createContextStack(params, this.modules);
9482
+ await evaluate(ast, contextStack);
9483
+ return contextStack.globalContext;
9484
+ },
9485
+ apply: async (fn, fnParams, params = {}) => {
9486
+ return this.apply(fn, fnParams, params);
9487
+ },
9488
+ };
8866
9489
  run(program, params = {}) {
8867
9490
  const ast = this.generateAst(program, params);
8868
9491
  const result = this.evaluate(ast, params);
9492
+ if (result instanceof Promise) {
9493
+ throw new TypeError('Unexpected async result in synchronous run(). Use lits.async.run() for async operations.');
9494
+ }
8869
9495
  return result;
8870
9496
  }
8871
9497
  context(programOrAst, params = {}) {
8872
9498
  const ast = typeof programOrAst === 'string' ? this.generateAst(programOrAst, params) : programOrAst;
8873
9499
  const contextStack = createContextStack(params, this.modules);
8874
- evaluate(ast, contextStack);
9500
+ const result = evaluate(ast, contextStack);
9501
+ if (result instanceof Promise) {
9502
+ throw new TypeError('Unexpected async result in synchronous context(). Use lits.async.context() for async operations.');
9503
+ }
8875
9504
  return contextStack.globalContext;
8876
9505
  }
8877
9506
  getUndefinedSymbols(programOrAst, params = {}) {
@@ -10137,13 +10766,9 @@ const assertNormalExpression = {
10137
10766
  }
10138
10767
  message ??= '';
10139
10768
  assertFunctionLike(func, sourceCodeInfo);
10140
- try {
10141
- executeFunction(func, [], contextStack, sourceCodeInfo);
10142
- }
10143
- catch {
10144
- return null;
10145
- }
10146
- throw new AssertionError(`Expected function to throw.${message}`, sourceCodeInfo);
10769
+ return tryCatch(() => chain(executeFunction(func, [], contextStack, sourceCodeInfo), () => {
10770
+ throw new AssertionError(`Expected function to throw.${message}`, sourceCodeInfo);
10771
+ }), () => null);
10147
10772
  },
10148
10773
  arity: { min: 1, max: 2 },
10149
10774
  },
@@ -10156,17 +10781,15 @@ const assertNormalExpression = {
10156
10781
  message ??= '';
10157
10782
  assertString(throwMessage, sourceCodeInfo);
10158
10783
  assertFunctionLike(func, sourceCodeInfo);
10159
- try {
10160
- executeFunction(func, [], contextStack, sourceCodeInfo);
10161
- }
10162
- catch (error) {
10784
+ return tryCatch(() => chain(executeFunction(func, [], contextStack, sourceCodeInfo), () => {
10785
+ throw new AssertionError(`Expected function to throw "${throwMessage}".${message}`, sourceCodeInfo);
10786
+ }), (error) => {
10163
10787
  const errorMessage = error.shortMessage;
10164
10788
  if (errorMessage !== throwMessage) {
10165
10789
  throw new AssertionError(`Expected function to throw "${throwMessage}", but thrown "${errorMessage}".${message}`, sourceCodeInfo);
10166
10790
  }
10167
10791
  return null;
10168
- }
10169
- throw new AssertionError(`Expected function to throw "${throwMessage}".${message}`, sourceCodeInfo);
10792
+ });
10170
10793
  },
10171
10794
  arity: { min: 2, max: 3 },
10172
10795
  },
@@ -10178,13 +10801,9 @@ const assertNormalExpression = {
10178
10801
  }
10179
10802
  message ??= '';
10180
10803
  assertFunctionLike(func, sourceCodeInfo);
10181
- try {
10182
- executeFunction(func, [], contextStack, sourceCodeInfo);
10183
- }
10184
- catch {
10804
+ return tryCatch(() => chain(executeFunction(func, [], contextStack, sourceCodeInfo), () => null), () => {
10185
10805
  throw new AssertionError(`Expected function not to throw.${message}`, sourceCodeInfo);
10186
- }
10187
- return null;
10806
+ });
10188
10807
  },
10189
10808
  arity: { min: 1, max: 2 },
10190
10809
  },
@@ -11572,14 +12191,13 @@ const gridFunctions = {
11572
12191
  evaluate: ([grid, predicate], sourceCodeInfo, contextStack, { executeFunction }) => {
11573
12192
  assertGrid(grid, sourceCodeInfo);
11574
12193
  assertFunctionLike(predicate, sourceCodeInfo);
12194
+ const cells = [];
11575
12195
  for (const row of grid) {
11576
12196
  for (const cell of row) {
11577
- if (!executeFunction(predicate, [cell], contextStack, sourceCodeInfo)) {
11578
- return false;
11579
- }
12197
+ cells.push(cell);
11580
12198
  }
11581
12199
  }
11582
- return true;
12200
+ return everySequential(cells, cell => executeFunction(predicate, [cell], contextStack, sourceCodeInfo));
11583
12201
  },
11584
12202
  arity: toFixedArity(2),
11585
12203
  },
@@ -11587,14 +12205,13 @@ const gridFunctions = {
11587
12205
  evaluate: ([grid, predicate], sourceCodeInfo, contextStack, { executeFunction }) => {
11588
12206
  assertGrid(grid, sourceCodeInfo);
11589
12207
  assertFunctionLike(predicate, sourceCodeInfo);
12208
+ const cells = [];
11590
12209
  for (const row of grid) {
11591
12210
  for (const cell of row) {
11592
- if (executeFunction(predicate, [cell], contextStack, sourceCodeInfo)) {
11593
- return true;
11594
- }
12211
+ cells.push(cell);
11595
12212
  }
11596
12213
  }
11597
- return false;
12214
+ return someSequential(cells, cell => executeFunction(predicate, [cell], contextStack, sourceCodeInfo));
11598
12215
  },
11599
12216
  arity: toFixedArity(2),
11600
12217
  },
@@ -11602,12 +12219,7 @@ const gridFunctions = {
11602
12219
  evaluate: ([grid, predicate], sourceCodeInfo, contextStack, { executeFunction }) => {
11603
12220
  assertGrid(grid, sourceCodeInfo);
11604
12221
  assertFunctionLike(predicate, sourceCodeInfo);
11605
- for (const row of grid) {
11606
- if (!executeFunction(predicate, [row], contextStack, sourceCodeInfo)) {
11607
- return false;
11608
- }
11609
- }
11610
- return true;
12222
+ return everySequential(Array.from(grid), row => executeFunction(predicate, [row], contextStack, sourceCodeInfo));
11611
12223
  },
11612
12224
  arity: toFixedArity(2),
11613
12225
  },
@@ -11615,12 +12227,7 @@ const gridFunctions = {
11615
12227
  evaluate: ([grid, predicate], sourceCodeInfo, contextStack, { executeFunction }) => {
11616
12228
  assertGrid(grid, sourceCodeInfo);
11617
12229
  assertFunctionLike(predicate, sourceCodeInfo);
11618
- for (const row of grid) {
11619
- if (executeFunction(predicate, [row], contextStack, sourceCodeInfo)) {
11620
- return true;
11621
- }
11622
- }
11623
- return false;
12230
+ return someSequential(Array.from(grid), row => executeFunction(predicate, [row], contextStack, sourceCodeInfo));
11624
12231
  },
11625
12232
  arity: toFixedArity(2),
11626
12233
  },
@@ -11629,12 +12236,7 @@ const gridFunctions = {
11629
12236
  assertGrid(grid, sourceCodeInfo);
11630
12237
  assertFunctionLike(predicate, sourceCodeInfo);
11631
12238
  const transposed = transpose(grid);
11632
- for (const row of transposed) {
11633
- if (!executeFunction(predicate, [row], contextStack, sourceCodeInfo)) {
11634
- return false;
11635
- }
11636
- }
11637
- return true;
12239
+ return everySequential(Array.from(transposed), row => executeFunction(predicate, [row], contextStack, sourceCodeInfo));
11638
12240
  },
11639
12241
  arity: toFixedArity(2),
11640
12242
  },
@@ -11643,12 +12245,7 @@ const gridFunctions = {
11643
12245
  assertGrid(grid, sourceCodeInfo);
11644
12246
  assertFunctionLike(predicate, sourceCodeInfo);
11645
12247
  const transposed = transpose(grid);
11646
- for (const row of transposed) {
11647
- if (executeFunction(predicate, [row], contextStack, sourceCodeInfo)) {
11648
- return true;
11649
- }
11650
- }
11651
- return false;
12248
+ return someSequential(Array.from(transposed), row => executeFunction(predicate, [row], contextStack, sourceCodeInfo));
11652
12249
  },
11653
12250
  arity: toFixedArity(2),
11654
12251
  },
@@ -11697,17 +12294,14 @@ const gridFunctions = {
11697
12294
  assertNumber(rows, sourceCodeInfo, { integer: true, positive: true });
11698
12295
  assertNumber(cols, sourceCodeInfo, { integer: true, positive: true });
11699
12296
  assertFunctionLike(generator, sourceCodeInfo);
11700
- const result = [];
11701
- for (let i = 0; i < rows; i += 1) {
11702
- const row = [];
11703
- for (let j = 0; j < cols; j += 1) {
11704
- const value = executeFunction(generator, [i, j], contextStack, sourceCodeInfo);
11705
- assertAny(value, sourceCodeInfo);
11706
- row.push(value);
11707
- }
11708
- result.push(row);
11709
- }
11710
- return result;
12297
+ return mapSequential(Array.from({ length: rows }), (_, i) => {
12298
+ return mapSequential(Array.from({ length: cols }), (__, j) => {
12299
+ return chain(executeFunction(generator, [i, j], contextStack, sourceCodeInfo), (value) => {
12300
+ assertAny(value, sourceCodeInfo);
12301
+ return value;
12302
+ });
12303
+ });
12304
+ });
11711
12305
  },
11712
12306
  arity: toFixedArity(3),
11713
12307
  },
@@ -11994,16 +12588,12 @@ const gridFunctions = {
11994
12588
  throw new LitsError(`All grids must have the same number of columns, but got ${cols} and ${grid[0].length}`, sourceCodeInfo);
11995
12589
  }
11996
12590
  });
11997
- const result = [];
11998
- for (let i = 0; i < rows; i += 1) {
11999
- const row = [];
12000
- for (let j = 0; j < cols; j += 1) {
12591
+ return mapSequential(Array.from({ length: rows }), (_, i) => {
12592
+ return mapSequential(Array.from({ length: cols }), (__, j) => {
12001
12593
  const args = grids.map(grid => grid[i][j]);
12002
- row.push(asAny(executeFunction(fn, args, contextStack, sourceCodeInfo)));
12003
- }
12004
- result.push(row);
12005
- }
12006
- return result;
12594
+ return chain(executeFunction(fn, args, contextStack, sourceCodeInfo), val => asAny(val));
12595
+ });
12596
+ });
12007
12597
  },
12008
12598
  arity: { min: 2 },
12009
12599
  },
@@ -12013,15 +12603,11 @@ const gridFunctions = {
12013
12603
  assertFunctionLike(fn, sourceCodeInfo);
12014
12604
  const rows = grid.length;
12015
12605
  const cols = grid[0].length;
12016
- const result = [];
12017
- for (let i = 0; i < rows; i += 1) {
12018
- const row = [];
12019
- for (let j = 0; j < cols; j += 1) {
12020
- row.push(asAny(executeFunction(fn, [grid[i][j], i, j], contextStack, sourceCodeInfo)));
12021
- }
12022
- result.push(row);
12023
- }
12024
- return result;
12606
+ return mapSequential(Array.from({ length: rows }), (_, i) => {
12607
+ return mapSequential(Array.from({ length: cols }), (__, j) => {
12608
+ return chain(executeFunction(fn, [grid[i][j], i, j], contextStack, sourceCodeInfo), val => asAny(val));
12609
+ });
12610
+ });
12025
12611
  },
12026
12612
  arity: toFixedArity(2),
12027
12613
  },
@@ -12029,13 +12615,13 @@ const gridFunctions = {
12029
12615
  evaluate: ([grid, fn, initialValue], sourceCodeInfo, contextStack, { executeFunction }) => {
12030
12616
  assertGrid(grid, sourceCodeInfo);
12031
12617
  assertFunctionLike(fn, sourceCodeInfo);
12032
- let accumulator = asAny(initialValue);
12618
+ const cells = [];
12033
12619
  for (const row of grid) {
12034
12620
  for (const cell of row) {
12035
- accumulator = executeFunction(fn, [accumulator, cell], contextStack, sourceCodeInfo);
12621
+ cells.push(cell);
12036
12622
  }
12037
12623
  }
12038
- return accumulator;
12624
+ return reduceSequential(cells, (accumulator, cell) => executeFunction(fn, [accumulator, cell], contextStack, sourceCodeInfo), asAny(initialValue));
12039
12625
  },
12040
12626
  arity: toFixedArity(3),
12041
12627
  },
@@ -12043,13 +12629,13 @@ const gridFunctions = {
12043
12629
  evaluate: ([grid, fn, initialValue], sourceCodeInfo, contextStack, { executeFunction }) => {
12044
12630
  assertGrid(grid, sourceCodeInfo);
12045
12631
  assertFunctionLike(fn, sourceCodeInfo);
12046
- let accumulator = asAny(initialValue);
12632
+ const cells = [];
12047
12633
  for (let i = 0; i < grid.length; i += 1) {
12048
12634
  for (let j = 0; j < grid[i].length; j += 1) {
12049
- accumulator = executeFunction(fn, [accumulator, grid[i][j], i, j], contextStack, sourceCodeInfo);
12635
+ cells.push({ cell: grid[i][j], i, j });
12050
12636
  }
12051
12637
  }
12052
- return accumulator;
12638
+ return reduceSequential(cells, (accumulator, { cell, i, j }) => executeFunction(fn, [accumulator, cell, i, j], contextStack, sourceCodeInfo), asAny(initialValue));
12053
12639
  },
12054
12640
  arity: toFixedArity(3),
12055
12641
  },
@@ -18165,10 +18751,11 @@ const vectorFunctions = {
18165
18751
  evaluate: ([length, generator], sourceCodeInfo, contextStack, { executeFunction }) => {
18166
18752
  assertNumber(length, sourceCodeInfo, { integer: true, nonNegative: true });
18167
18753
  assertFunctionLike(generator, sourceCodeInfo);
18168
- return Array.from({ length }, (_, i) => {
18169
- const value = executeFunction(generator, [i], contextStack, sourceCodeInfo);
18170
- assertNumber(value, sourceCodeInfo, { finite: true });
18171
- return value;
18754
+ return mapSequential(Array.from({ length }), (_, i) => {
18755
+ return chain(executeFunction(generator, [i], contextStack, sourceCodeInfo), (value) => {
18756
+ assertNumber(value, sourceCodeInfo, { finite: true });
18757
+ return value;
18758
+ });
18172
18759
  });
18173
18760
  },
18174
18761
  arity: toFixedArity(2),
@@ -26799,16 +27386,17 @@ const abundantSequence = {
26799
27386
  'abundant?': n => isAbundant(n),
26800
27387
  'abundant-take-while': (takeWhile) => {
26801
27388
  const abundants = [];
26802
- for (let i = 2;; i += 1) {
26803
- if (!isAbundant(i)) {
26804
- continue;
26805
- }
26806
- if (!takeWhile(i, abundants.length)) {
26807
- break;
26808
- }
26809
- abundants.push(i);
27389
+ function loop(i) {
27390
+ if (!isAbundant(i))
27391
+ return loop(i + 1);
27392
+ return chain(takeWhile(i, abundants.length), (keep) => {
27393
+ if (!keep)
27394
+ return abundants;
27395
+ abundants.push(i);
27396
+ return loop(i + 1);
27397
+ });
26810
27398
  }
26811
- return abundants;
27399
+ return loop(2);
26812
27400
  },
26813
27401
  };
26814
27402
 
@@ -26853,15 +27441,20 @@ const arithmeticNormalExpressions = {
26853
27441
  assertNumber(start, sourceCodeInfo, { finite: true });
26854
27442
  assertNumber(step, sourceCodeInfo, { finite: true });
26855
27443
  assertFunctionLike(fn, sourceCodeInfo);
27444
+ const s = start;
27445
+ const d = step;
27446
+ const f = fn;
26856
27447
  const arithmetic = [];
26857
- for (let i = 0;; i += 1) {
26858
- const value = start + i * step;
26859
- if (!(executeFunction)(fn, [value, i], contextStack, sourceCodeInfo)) {
26860
- break;
26861
- }
26862
- arithmetic[i] = value;
27448
+ function loop(i) {
27449
+ const value = s + i * d;
27450
+ return chain(executeFunction(f, [value, i], contextStack, sourceCodeInfo), (keep) => {
27451
+ if (!keep)
27452
+ return arithmetic;
27453
+ arithmetic.push(value);
27454
+ return loop(i + 1);
27455
+ });
26863
27456
  }
26864
- return arithmetic;
27457
+ return loop(0);
26865
27458
  },
26866
27459
  arity: toFixedArity(3),
26867
27460
  },
@@ -26927,28 +27520,21 @@ function getBernoulliSeq(length) {
26927
27520
  * @returns Array of Bernoulli numbers generated until predicate returns false
26928
27521
  */
26929
27522
  function generateBernoulli(predicate) {
26930
- const batchSize = 100;
26931
- // Start with computing the Bernoulli numbers
26932
27523
  const bernoulli = [1];
26933
- let n = 1;
26934
- // Continue generating as long as the predicate returns true
26935
- while (true) {
26936
- // Generate a batch of numbers at a time for efficiency
26937
- const targetLength = bernoulli.length + batchSize;
26938
- for (; n < targetLength; n++) {
26939
- let sum = 0;
26940
- for (let k = 0; k < n; k++) {
26941
- sum += binomialCoefficient(n + 1, k) * bernoulli[k];
26942
- }
26943
- const newValue = n > 1 && n % 2 === 1 ? 0 : -sum / (n + 1);
26944
- // Check if we should continue
26945
- if (!predicate(newValue, n)) {
26946
- // We're done, return the generated sequence (including the last value)
27524
+ function loop(n) {
27525
+ let sum = 0;
27526
+ for (let k = 0; k < n; k++) {
27527
+ sum += binomialCoefficient(n + 1, k) * bernoulli[k];
27528
+ }
27529
+ const newValue = n > 1 && n % 2 === 1 ? 0 : -sum / (n + 1);
27530
+ return chain(predicate(newValue, n), (keep) => {
27531
+ if (!keep)
26947
27532
  return bernoulli;
26948
- }
26949
27533
  bernoulli.push(newValue);
26950
- }
27534
+ return loop(n + 1);
27535
+ });
26951
27536
  }
27537
+ return loop(1);
26952
27538
  }
26953
27539
  const bernoulliNormalExpressions = {
26954
27540
  'bernoulli-seq': {
@@ -26969,8 +27555,8 @@ const bernoulliNormalExpressions = {
26969
27555
  'bernoulli-take-while': {
26970
27556
  evaluate: ([fn], sourceCodeInfo, contextStack, { executeFunction }) => {
26971
27557
  assertFunctionLike(fn, sourceCodeInfo);
26972
- const bernoulli = generateBernoulli((value, index) => !!(executeFunction)(fn, [value, index], contextStack));
26973
- return bernoulli;
27558
+ const f = fn;
27559
+ return generateBernoulli((value, index) => chain(executeFunction(f, [value, index], contextStack), val => !!val));
26974
27560
  },
26975
27561
  arity: toFixedArity(1),
26976
27562
  },
@@ -27059,16 +27645,17 @@ const primeSequence = {
27059
27645
  'prime?': n => isPrime(n),
27060
27646
  'prime-take-while': (takeWhile) => {
27061
27647
  const primes = [];
27062
- for (let i = 2;; i += 1) {
27063
- if (!isPrime(i)) {
27064
- continue;
27065
- }
27066
- if (!takeWhile(i, primes.length)) {
27067
- break;
27068
- }
27069
- primes.push(i);
27648
+ function loop(i) {
27649
+ if (!isPrime(i))
27650
+ return loop(i + 1);
27651
+ return chain(takeWhile(i, primes.length), (keep) => {
27652
+ if (!keep)
27653
+ return primes;
27654
+ primes.push(i);
27655
+ return loop(i + 1);
27656
+ });
27070
27657
  }
27071
- return primes;
27658
+ return loop(2);
27072
27659
  },
27073
27660
  };
27074
27661
 
@@ -27093,16 +27680,17 @@ const compositeSequence = {
27093
27680
  'composite?': n => isComposite(n),
27094
27681
  'composite-take-while': (takeWhile) => {
27095
27682
  const composites = [];
27096
- for (let i = 4;; i += 1) {
27097
- if (!isComposite(i)) {
27098
- continue;
27099
- }
27100
- if (!takeWhile(i, composites.length)) {
27101
- break;
27102
- }
27103
- composites.push(i);
27683
+ function loop(i) {
27684
+ if (!isComposite(i))
27685
+ return loop(i + 1);
27686
+ return chain(takeWhile(i, composites.length), (keep) => {
27687
+ if (!keep)
27688
+ return composites;
27689
+ composites.push(i);
27690
+ return loop(i + 1);
27691
+ });
27104
27692
  }
27105
- return composites;
27693
+ return loop(4);
27106
27694
  },
27107
27695
  };
27108
27696
 
@@ -27126,16 +27714,17 @@ const deficientSequence = {
27126
27714
  'deficient?': n => isDeficient(n),
27127
27715
  'deficient-take-while': (takeWhile) => {
27128
27716
  const deficients = [];
27129
- for (let i = 1;; i += 1) {
27130
- if (!isDeficient(i)) {
27131
- continue;
27132
- }
27133
- if (!takeWhile(i, deficients.length)) {
27134
- break;
27135
- }
27136
- deficients.push(i);
27717
+ function loop(i) {
27718
+ if (!isDeficient(i))
27719
+ return loop(i + 1);
27720
+ return chain(takeWhile(i, deficients.length), (keep) => {
27721
+ if (!keep)
27722
+ return deficients;
27723
+ deficients.push(i);
27724
+ return loop(i + 1);
27725
+ });
27137
27726
  }
27138
- return deficients;
27727
+ return loop(1);
27139
27728
  },
27140
27729
  };
27141
27730
 
@@ -27295,15 +27884,20 @@ const geometricNormalExpressions = {
27295
27884
  assertNumber(start, sourceCodeInfo, { finite: true });
27296
27885
  assertNumber(ratio, sourceCodeInfo, { finite: true });
27297
27886
  assertFunctionLike(fn, sourceCodeInfo);
27887
+ const s = start;
27888
+ const r = ratio;
27889
+ const f = fn;
27298
27890
  const geometric = [];
27299
- for (let i = 0;; i += 1) {
27300
- const value = start * ratio ** i;
27301
- if (!(executeFunction)(fn, [value, i], contextStack, sourceCodeInfo)) {
27302
- break;
27303
- }
27304
- geometric[i] = value;
27891
+ function loop(i) {
27892
+ const value = s * r ** i;
27893
+ return chain(executeFunction(f, [value, i], contextStack, sourceCodeInfo), (keep) => {
27894
+ if (!keep)
27895
+ return geometric;
27896
+ geometric.push(value);
27897
+ return loop(i + 1);
27898
+ });
27305
27899
  }
27306
- return geometric;
27900
+ return loop(0);
27307
27901
  },
27308
27902
  arity: toFixedArity(3),
27309
27903
  },
@@ -27335,18 +27929,21 @@ function getGolombSeq(n) {
27335
27929
  return golomb.slice(1);
27336
27930
  }
27337
27931
  function generateGolombSeq(pred) {
27338
- if (!pred(1, 0)) {
27339
- return [];
27340
- }
27341
27932
  const golomb = [0, 1];
27342
- for (let i = 2;; i++) {
27343
- const golombNumber = 1 + golomb[i - golomb[golomb[i - 1]]];
27344
- if (!pred(golombNumber, i - 1)) {
27345
- break;
27933
+ return chain(pred(1, 0), (keepFirst) => {
27934
+ if (!keepFirst)
27935
+ return [];
27936
+ function loop(i) {
27937
+ const golombNumber = 1 + golomb[i - golomb[golomb[i - 1]]];
27938
+ return chain(pred(golombNumber, i - 1), (keep) => {
27939
+ if (!keep)
27940
+ return golomb.slice(1);
27941
+ golomb.push(golombNumber);
27942
+ return loop(i + 1);
27943
+ });
27346
27944
  }
27347
- golomb.push(golombNumber);
27348
- }
27349
- return golomb.slice(1);
27945
+ return loop(2);
27946
+ });
27350
27947
  }
27351
27948
  const golombSequence = {
27352
27949
  'golomb-seq': length => getGolombSeq(length),
@@ -27401,23 +27998,17 @@ const happySequence = {
27401
27998
  'happy?': n => isHappyNumber(n),
27402
27999
  'happy-take-while': (takeWhile) => {
27403
28000
  const happyNumbers = [];
27404
- for (let i = 1;; i++) {
27405
- let n = i;
27406
- const seen = new Set();
27407
- while (n !== 1 && !seen.has(n)) {
27408
- seen.add(n);
27409
- n = String(n)
27410
- .split('')
27411
- .reduce((sum, digit) => sum + Number(digit) ** 2, 0);
27412
- }
27413
- if (n === 1) {
27414
- if (!takeWhile(i, happyNumbers.length)) {
27415
- break;
27416
- }
28001
+ function loop(i) {
28002
+ if (!isHappyNumber(i))
28003
+ return loop(i + 1);
28004
+ return chain(takeWhile(i, happyNumbers.length), (keep) => {
28005
+ if (!keep)
28006
+ return happyNumbers;
27417
28007
  happyNumbers.push(i);
27418
- }
28008
+ return loop(i + 1);
28009
+ });
27419
28010
  }
27420
- return happyNumbers;
28011
+ return loop(1);
27421
28012
  },
27422
28013
  };
27423
28014
 
@@ -27500,19 +28091,23 @@ const lookAndSaySequence = {
27500
28091
  return lookAndSay;
27501
28092
  },
27502
28093
  'look-and-say-take-while': (takeWhile) => {
27503
- if (!takeWhile('1', 0)) {
27504
- return [];
27505
- }
27506
- const lookAndSay = ['1'];
27507
- for (let i = 1;; i += 1) {
27508
- const prev = lookAndSay[i - 1];
27509
- const next = prev.replace(/(\d)\1*/g, match => `${match.length}${match[0]}`);
27510
- if (!takeWhile(next, i)) {
27511
- break;
28094
+ const lookAndSay = [];
28095
+ return chain(takeWhile('1', 0), (keepFirst) => {
28096
+ if (!keepFirst)
28097
+ return lookAndSay;
28098
+ lookAndSay.push('1');
28099
+ function loop(i) {
28100
+ const prev = lookAndSay[i - 1];
28101
+ const next = prev.replace(/(\d)\1*/g, match => `${match.length}${match[0]}`);
28102
+ return chain(takeWhile(next, i), (keep) => {
28103
+ if (!keep)
28104
+ return lookAndSay;
28105
+ lookAndSay.push(next);
28106
+ return loop(i + 1);
28107
+ });
27512
28108
  }
27513
- lookAndSay[i] = next;
27514
- }
27515
- return lookAndSay;
28109
+ return loop(1);
28110
+ });
27516
28111
  },
27517
28112
  'look-and-say?': n => isLookAndSay(n),
27518
28113
  };
@@ -27620,42 +28215,45 @@ function generateLuckyNumbers(predicate) {
27620
28215
  const luckyNumbers = [1]; // 1 is always the first lucky number
27621
28216
  let count = 1;
27622
28217
  // Check if we should continue after the first number
27623
- if (!predicate(1, 0)) {
27624
- return [];
27625
- }
27626
- // Continue the sieve process
27627
- let index = 1; // Start with the second element (index 1, which is 3)
27628
- while (index < filteredNumbers.length) {
27629
- // Get the current lucky number
27630
- const luckyNumber = filteredNumbers[index];
27631
- // Check if we should continue
27632
- if (!predicate(luckyNumber, count)) {
27633
- break;
27634
- }
27635
- // Add to result
27636
- luckyNumbers.push(luckyNumber);
27637
- count++;
27638
- // Apply the sieve
27639
- const step = luckyNumber;
27640
- const newFiltered = [];
27641
- for (let i = 0; i < filteredNumbers.length; i++) {
27642
- if ((i + 1) % step !== 0) { // Keep numbers not at positions divisible by step
27643
- newFiltered.push(filteredNumbers[i]);
27644
- }
27645
- }
27646
- filteredNumbers = newFiltered;
27647
- index++;
27648
- // If we're running low on numbers, extend the sequence
27649
- if (index >= filteredNumbers.length - 5) {
27650
- const lastNum = filteredNumbers[filteredNumbers.length - 1];
27651
- let next = lastNum + 2;
27652
- while (filteredNumbers.length < index + 1000) {
27653
- filteredNumbers.push(next);
27654
- next += 2;
27655
- }
28218
+ return chain(predicate(1, 0), (keepFirst) => {
28219
+ if (!keepFirst)
28220
+ return [];
28221
+ // Continue the sieve process
28222
+ let index = 1; // Start with the second element (index 1, which is 3)
28223
+ function loop() {
28224
+ // Get the current lucky number
28225
+ const luckyNumber = filteredNumbers[index];
28226
+ // Check if we should continue
28227
+ return chain(predicate(luckyNumber, count), (keep) => {
28228
+ if (!keep)
28229
+ return luckyNumbers;
28230
+ // Add to result
28231
+ luckyNumbers.push(luckyNumber);
28232
+ count++;
28233
+ // Apply the sieve
28234
+ const step = luckyNumber;
28235
+ const newFiltered = [];
28236
+ for (let i = 0; i < filteredNumbers.length; i++) {
28237
+ if ((i + 1) % step !== 0) { // Keep numbers not at positions divisible by step
28238
+ newFiltered.push(filteredNumbers[i]);
28239
+ }
28240
+ }
28241
+ filteredNumbers = newFiltered;
28242
+ index++;
28243
+ // If we're running low on numbers, extend the sequence
28244
+ if (index >= filteredNumbers.length - 5) {
28245
+ const lastNum = filteredNumbers[filteredNumbers.length - 1];
28246
+ let next = lastNum + 2;
28247
+ while (filteredNumbers.length < index + 1000) {
28248
+ filteredNumbers.push(next);
28249
+ next += 2;
28250
+ }
28251
+ }
28252
+ return loop();
28253
+ });
27656
28254
  }
27657
- }
27658
- return luckyNumbers;
28255
+ return loop();
28256
+ });
27659
28257
  }
27660
28258
  /**
27661
28259
  * Generates lucky numbers up to a specified length or count
@@ -27818,32 +28416,37 @@ const padovanSequence = {
27818
28416
  'padovan?': n => isPadovan(n),
27819
28417
  'padovan-take-while': (takeWhile) => {
27820
28418
  const padovan = [];
27821
- if (!takeWhile(1, 0)) {
27822
- return padovan;
27823
- }
27824
- padovan.push(1);
27825
- if (!takeWhile(1, 1)) {
27826
- return padovan;
27827
- }
27828
- padovan.push(1);
27829
- if (!takeWhile(1, 2)) {
27830
- return padovan;
27831
- }
27832
- padovan.push(1);
27833
- let a = 1;
27834
- let b = 1;
27835
- let c = 1;
27836
- for (let i = 4;; i += 1) {
27837
- const temp = a + b;
27838
- a = b;
27839
- b = c;
27840
- c = temp;
27841
- if (!takeWhile(c, i)) {
27842
- break;
27843
- }
27844
- padovan.push(c);
27845
- }
27846
- return padovan;
28419
+ return chain(takeWhile(1, 0), (keep0) => {
28420
+ if (!keep0)
28421
+ return padovan;
28422
+ padovan.push(1);
28423
+ return chain(takeWhile(1, 1), (keep1) => {
28424
+ if (!keep1)
28425
+ return padovan;
28426
+ padovan.push(1);
28427
+ return chain(takeWhile(1, 2), (keep2) => {
28428
+ if (!keep2)
28429
+ return padovan;
28430
+ padovan.push(1);
28431
+ let a = 1;
28432
+ let b = 1;
28433
+ let c = 1;
28434
+ function loop(i) {
28435
+ const temp = a + b;
28436
+ a = b;
28437
+ b = c;
28438
+ c = temp;
28439
+ return chain(takeWhile(c, i), (keep) => {
28440
+ if (!keep)
28441
+ return padovan;
28442
+ padovan.push(c);
28443
+ return loop(i + 1);
28444
+ });
28445
+ }
28446
+ return loop(4);
28447
+ });
28448
+ });
28449
+ });
27847
28450
  },
27848
28451
  };
27849
28452
 
@@ -27905,14 +28508,16 @@ const perfectCubeSequence = {
27905
28508
  'perfect-cube?': n => n > 0 && Number.isInteger(Math.cbrt(n)),
27906
28509
  'perfect-cube-take-while': (takeWhile) => {
27907
28510
  const perfectcubes = [];
27908
- for (let i = 1;; i++) {
28511
+ function loop(i) {
27909
28512
  const value = i ** 3;
27910
- if (!takeWhile(value, i)) {
27911
- break;
27912
- }
27913
- perfectcubes.push(value);
28513
+ return chain(takeWhile(value, i), (keep) => {
28514
+ if (!keep)
28515
+ return perfectcubes;
28516
+ perfectcubes.push(value);
28517
+ return loop(i + 1);
28518
+ });
27914
28519
  }
27915
- return perfectcubes;
28520
+ return loop(1);
27916
28521
  },
27917
28522
  };
27918
28523
 
@@ -27957,15 +28562,17 @@ const perfectPowerSequence = {
27957
28562
  'perfect-power?': n => perfectPower(n) !== null,
27958
28563
  'perfect-power-take-while': (takeWhile) => {
27959
28564
  const perfectPowers = [];
27960
- for (let i = 1;; i++) {
27961
- if (perfectPower(i)) {
27962
- if (!takeWhile(i, perfectPowers.length)) {
27963
- break;
27964
- }
28565
+ function loop(i) {
28566
+ if (!perfectPower(i))
28567
+ return loop(i + 1);
28568
+ return chain(takeWhile(i, perfectPowers.length), (keep) => {
28569
+ if (!keep)
28570
+ return perfectPowers;
27965
28571
  perfectPowers.push(i);
27966
- }
28572
+ return loop(i + 1);
28573
+ });
27967
28574
  }
27968
- return perfectPowers;
28575
+ return loop(1);
27969
28576
  },
27970
28577
  };
27971
28578
 
@@ -27980,14 +28587,16 @@ const perfectSquareSequence = {
27980
28587
  'perfect-square?': n => n > 0 && Number.isInteger(Math.sqrt(n)),
27981
28588
  'perfect-square-take-while': (takeWhile) => {
27982
28589
  const perfectSquares = [];
27983
- for (let i = 1;; i++) {
28590
+ function loop(i) {
27984
28591
  const value = i ** 2;
27985
- if (!takeWhile(value, i)) {
27986
- break;
27987
- }
27988
- perfectSquares.push(value);
28592
+ return chain(takeWhile(value, i), (keep) => {
28593
+ if (!keep)
28594
+ return perfectSquares;
28595
+ perfectSquares.push(value);
28596
+ return loop(i + 1);
28597
+ });
27989
28598
  }
27990
- return perfectSquares;
28599
+ return loop(1);
27991
28600
  },
27992
28601
  };
27993
28602
 
@@ -28008,15 +28617,19 @@ const poligonalNormalExpressions = {
28008
28617
  evaluate: ([sides, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
28009
28618
  assertNumber(sides, sourceCodeInfo, { integer: true, gte: 3 });
28010
28619
  assertFunctionLike(fn, sourceCodeInfo);
28620
+ const s = sides;
28621
+ const f = fn;
28011
28622
  const polygonal = [];
28012
- for (let i = 1;; i += 1) {
28013
- const value = (i * i * (sides - 2) - i * (sides - 4)) / 2;
28014
- if (!(executeFunction)(fn, [value, i], contextStack, sourceCodeInfo)) {
28015
- break;
28016
- }
28017
- polygonal[i - 1] = (i * i * (sides - 2) - i * (sides - 4)) / 2;
28623
+ function loop(i) {
28624
+ const value = (i * i * (s - 2) - i * (s - 4)) / 2;
28625
+ return chain(executeFunction(f, [value, i], contextStack, sourceCodeInfo), (keep) => {
28626
+ if (!keep)
28627
+ return polygonal;
28628
+ polygonal.push(value);
28629
+ return loop(i + 1);
28630
+ });
28018
28631
  }
28019
- return polygonal;
28632
+ return loop(1);
28020
28633
  },
28021
28634
  arity: toFixedArity(2),
28022
28635
  },
@@ -28080,23 +28693,29 @@ function generateRecamanSequence(n) {
28080
28693
  const recamanSequence = {
28081
28694
  'recaman-seq': length => generateRecamanSequence(length),
28082
28695
  'recaman-take-while': (takeWhile) => {
28083
- if (!takeWhile(0, 0))
28084
- return [];
28085
- const sequence = [0];
28696
+ const sequence = [];
28086
28697
  const seen = new Set([0]);
28087
- for (let i = 1;; i++) {
28088
- // Try to go backward
28089
- let next = sequence[i - 1] - i;
28090
- // If that's not positive or already seen, go forward
28091
- if (next <= 0 || seen.has(next)) {
28092
- next = sequence[i - 1] + i;
28093
- }
28094
- if (!takeWhile(next, i))
28095
- break;
28096
- sequence.push(next);
28097
- seen.add(next);
28098
- }
28099
- return sequence;
28698
+ return chain(takeWhile(0, 0), (keepFirst) => {
28699
+ if (!keepFirst)
28700
+ return sequence;
28701
+ sequence.push(0);
28702
+ function loop(i) {
28703
+ // Try to go backward
28704
+ let next = sequence[i - 1] - i;
28705
+ // If that's not positive or already seen, go forward
28706
+ if (next <= 0 || seen.has(next)) {
28707
+ next = sequence[i - 1] + i;
28708
+ }
28709
+ return chain(takeWhile(next, i), (keep) => {
28710
+ if (!keep)
28711
+ return sequence;
28712
+ sequence.push(next);
28713
+ seen.add(next);
28714
+ return loop(i + 1);
28715
+ });
28716
+ }
28717
+ return loop(1);
28718
+ });
28100
28719
  },
28101
28720
  'recaman?': () => true,
28102
28721
  };
@@ -28120,14 +28739,16 @@ const thueMorseSequence = {
28120
28739
  },
28121
28740
  'thue-morse-take-while': (takeWhile) => {
28122
28741
  const thueMorse = [];
28123
- for (let i = 0;; i += 1) {
28742
+ function loop(i) {
28124
28743
  const value = countSetBits(i) % 2;
28125
- if (!takeWhile(value, i)) {
28126
- break;
28127
- }
28128
- thueMorse[i] = value;
28744
+ return chain(takeWhile(value, i), (keep) => {
28745
+ if (!keep)
28746
+ return thueMorse;
28747
+ thueMorse.push(value);
28748
+ return loop(i + 1);
28749
+ });
28129
28750
  }
28130
- return thueMorse;
28751
+ return loop(0);
28131
28752
  },
28132
28753
  'thue-morse?': n => n === 1 || n === 0,
28133
28754
  };
@@ -28251,16 +28872,16 @@ function getFiniteNumberSequence(name, sequence) {
28251
28872
  return {
28252
28873
  [`${name}-seq`]: createSeqNormalExpression(length => sequence.slice(0, length), sequence.length),
28253
28874
  [`${name}-take-while`]: createTakeWhileNormalExpression((takeWhile) => {
28254
- let i = 0;
28255
- for (i = 0;; i += 1) {
28256
- if (i >= sequence.length) {
28257
- break;
28258
- }
28259
- if (!takeWhile(sequence[i], i)) {
28260
- break;
28261
- }
28875
+ function loop(i) {
28876
+ if (i >= sequence.length)
28877
+ return sequence.slice(0, i);
28878
+ return chain(takeWhile(sequence[i], i), (keep) => {
28879
+ if (!keep)
28880
+ return sequence.slice(0, i);
28881
+ return loop(i + 1);
28882
+ });
28262
28883
  }
28263
- return sequence.slice(0, i);
28884
+ return loop(0);
28264
28885
  }, sequence.length),
28265
28886
  [`${name}-nth`]: createNthNormalExpression(() => sequence, sequence.length),
28266
28887
  [`${name}?`]: createNumberPredNormalExpression(n => sequence.includes(n)),
@@ -28313,14 +28934,16 @@ function createTakeWhileNormalExpression(takeWhileFunction, maxLength) {
28313
28934
  evaluate: (params, sourceCodeInfo, contextStack, { executeFunction }) => {
28314
28935
  const fn = params[0];
28315
28936
  assertFunctionLike(fn, sourceCodeInfo);
28316
- const result = takeWhileFunction((value, index) => !!executeFunction(fn, [value, index], contextStack), sourceCodeInfo);
28317
- if (typeof result[0] === 'number') {
28318
- /* v8 ignore next 3 */
28319
- if (result.some(n => n > Number.MAX_SAFE_INTEGER)) {
28320
- throw new LitsError('Result exceeds maximum safe integer', sourceCodeInfo);
28937
+ const result = takeWhileFunction((value, index) => chain(executeFunction(fn, [value, index], contextStack), val => !!val), sourceCodeInfo);
28938
+ return chain(result, (resolved) => {
28939
+ if (typeof resolved[0] === 'number') {
28940
+ /* v8 ignore next 3 */
28941
+ if (resolved.some(n => n > Number.MAX_SAFE_INTEGER)) {
28942
+ throw new LitsError('Result exceeds maximum safe integer', sourceCodeInfo);
28943
+ }
28321
28944
  }
28322
- }
28323
- return result;
28945
+ return resolved;
28946
+ });
28324
28947
  },
28325
28948
  arity: typeof maxLength === 'number' ? { max: 1 } : toFixedArity(1),
28326
28949
  };
@@ -29789,38 +30412,30 @@ function update(coll, key, fn, params, contextStack, executeFunction, sourceCode
29789
30412
  if (isObj(coll)) {
29790
30413
  assertString(key, sourceCodeInfo);
29791
30414
  const result = { ...coll };
29792
- result[key] = executeFunction(fn, [result[key], ...params], contextStack, sourceCodeInfo);
29793
- return result;
30415
+ return chain(executeFunction(fn, [result[key], ...params], contextStack, sourceCodeInfo), (val) => {
30416
+ result[key] = val;
30417
+ return result;
30418
+ });
29794
30419
  }
29795
30420
  else {
29796
30421
  assertNumber(key, sourceCodeInfo);
29797
30422
  const intKey = toNonNegativeInteger(key);
29798
30423
  assertNumber(intKey, sourceCodeInfo, { lte: coll.length });
29799
30424
  if (Array.isArray(coll)) {
29800
- const result = coll.map((elem, index) => {
30425
+ return chain(mapSequential(Array.from({ length: coll.length + (intKey === coll.length ? 1 : 0) }), (_, index) => {
29801
30426
  if (intKey === index)
29802
- return executeFunction(fn, [elem, ...params], contextStack, sourceCodeInfo);
29803
- return elem;
29804
- });
29805
- if (intKey === coll.length)
29806
- result[intKey] = executeFunction(fn, [undefined, ...params], contextStack, sourceCodeInfo);
29807
- return result;
30427
+ return executeFunction(fn, [coll[index], ...params], contextStack, sourceCodeInfo);
30428
+ return coll[index];
30429
+ }), result => result);
29808
30430
  }
29809
30431
  else {
29810
- const result = coll.split('').map((elem, index) => {
30432
+ const chars = coll.split('');
30433
+ return chain(mapSequential(Array.from({ length: chars.length + (intKey === chars.length ? 1 : 0) }), (_, index) => {
29811
30434
  if (intKey === index) {
29812
- return asString(executeFunction(fn, [elem, ...params], contextStack, sourceCodeInfo), sourceCodeInfo, {
29813
- char: true,
29814
- });
30435
+ return chain(executeFunction(fn, [chars[index], ...params], contextStack, sourceCodeInfo), val => asString(val, sourceCodeInfo, { char: true }));
29815
30436
  }
29816
- return elem;
29817
- });
29818
- if (intKey === coll.length) {
29819
- result[intKey] = asString(executeFunction(fn, [undefined, ...params], contextStack, sourceCodeInfo), sourceCodeInfo, {
29820
- char: true,
29821
- });
29822
- }
29823
- return result.join('');
30437
+ return chars[index];
30438
+ }), result => result.join(''));
29824
30439
  }
29825
30440
  }
29826
30441
  }
@@ -30025,13 +30640,18 @@ cu.update(
30025
30640
  const parentKey = asStringOrNumber(keys[keys.length - 2], sourceCodeInfo);
30026
30641
  if (Array.isArray(innerCollMeta.parent)) {
30027
30642
  assertNumber(parentKey, sourceCodeInfo);
30028
- innerCollMeta.parent[parentKey] = update(innerCollMeta.coll, lastKey, fn, params, contextStack, executeFunction, sourceCodeInfo);
30643
+ return chain(update(innerCollMeta.coll, lastKey, fn, params, contextStack, executeFunction, sourceCodeInfo), (updated) => {
30644
+ innerCollMeta.parent[parentKey] = updated;
30645
+ return coll;
30646
+ });
30029
30647
  }
30030
30648
  else {
30031
30649
  assertString(parentKey, sourceCodeInfo);
30032
- innerCollMeta.parent[parentKey] = update(innerCollMeta.coll, lastKey, fn, params, contextStack, executeFunction, sourceCodeInfo);
30650
+ return chain(update(innerCollMeta.coll, lastKey, fn, params, contextStack, executeFunction, sourceCodeInfo), (updated) => {
30651
+ innerCollMeta.parent[parentKey] = updated;
30652
+ return coll;
30653
+ });
30033
30654
  }
30034
- return coll;
30035
30655
  },
30036
30656
  arity: { min: 3 },
30037
30657
  docs: {
@@ -30092,21 +30712,15 @@ cu.update-in(
30092
30712
  assertColl(coll, sourceCodeInfo);
30093
30713
  assertFunctionLike(fn, sourceCodeInfo);
30094
30714
  if (Array.isArray(coll)) {
30095
- const result = coll.filter((elem, index) => executeFunction(fn, [elem, index], contextStack, sourceCodeInfo));
30096
- return result;
30715
+ return filterSequential(coll, (elem, index) => executeFunction(fn, [elem, index], contextStack, sourceCodeInfo));
30097
30716
  }
30098
30717
  if (typeof coll === 'string') {
30099
- return coll
30100
- .split('')
30101
- .filter((elem, index) => executeFunction(fn, [elem, index], contextStack, sourceCodeInfo))
30102
- .join('');
30718
+ return chain(filterSequential(coll.split(''), (elem, index) => executeFunction(fn, [elem, index], contextStack, sourceCodeInfo)), filtered => filtered.join(''));
30103
30719
  }
30104
- return Object.entries(coll)
30105
- .filter(([key, value]) => executeFunction(fn, [value, key], contextStack, sourceCodeInfo))
30106
- .reduce((result, [key, value]) => {
30720
+ return chain(filterSequential(Object.entries(coll), ([key, value]) => executeFunction(fn, [value, key], contextStack, sourceCodeInfo)), filtered => filtered.reduce((result, [key, value]) => {
30107
30721
  result[key] = value;
30108
30722
  return result;
30109
- }, {});
30723
+ }, {}));
30110
30724
  },
30111
30725
  arity: toFixedArity(2),
30112
30726
  docs: {
@@ -30134,18 +30748,17 @@ cu.update-in(
30134
30748
  assertColl(coll, sourceCodeInfo);
30135
30749
  assertFunctionLike(fn, sourceCodeInfo);
30136
30750
  if (Array.isArray(coll)) {
30137
- return coll.map((elem, index) => executeFunction(fn, [elem, index], contextStack, sourceCodeInfo));
30751
+ return mapSequential(coll, (elem, index) => executeFunction(fn, [elem, index], contextStack, sourceCodeInfo));
30138
30752
  }
30139
30753
  if (typeof coll === 'string') {
30140
- return coll
30141
- .split('')
30142
- .map((elem, index) => executeFunction(fn, [elem, index], contextStack, sourceCodeInfo))
30143
- .join('');
30754
+ return chain(mapSequential(coll.split(''), (elem, index) => executeFunction(fn, [elem, index], contextStack, sourceCodeInfo)), mapped => mapped.join(''));
30144
30755
  }
30145
- return Object.entries(coll)
30146
- .reduce((acc, [key, value]) => {
30147
- acc[key] = executeFunction(fn, [value, key], contextStack, sourceCodeInfo);
30148
- return acc;
30756
+ const entries = Object.entries(coll);
30757
+ return reduceSequential(entries, (acc, [key, value]) => {
30758
+ return chain(executeFunction(fn, [value, key], contextStack, sourceCodeInfo), (result) => {
30759
+ acc[key] = result;
30760
+ return acc;
30761
+ });
30149
30762
  }, {});
30150
30763
  },
30151
30764
  arity: toFixedArity(2),
@@ -30180,23 +30793,17 @@ cu.update-in(
30180
30793
  assertString(initial, sourceCodeInfo);
30181
30794
  if (coll.length === 0)
30182
30795
  return initial;
30183
- return coll.split('').reduce((result, elem, index) => {
30184
- return executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo);
30185
- }, initial);
30796
+ return reduceSequential(coll.split('').map((elem, index) => ({ elem, index })), (result, { elem, index }) => executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo), initial);
30186
30797
  }
30187
30798
  else if (Array.isArray(coll)) {
30188
30799
  if (coll.length === 0)
30189
30800
  return initial;
30190
- return coll.reduce((result, elem, index) => {
30191
- return executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo);
30192
- }, initial);
30801
+ return reduceSequential(coll.map((elem, index) => ({ elem, index })), (result, { elem, index }) => executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo), initial);
30193
30802
  }
30194
30803
  else {
30195
30804
  if (Object.keys(coll).length === 0)
30196
30805
  return initial;
30197
- return Object.entries(coll).reduce((result, [key, elem]) => {
30198
- return executeFunction(fn, [result, elem, key], contextStack, sourceCodeInfo);
30199
- }, initial);
30806
+ return reduceSequential(Object.entries(coll), (result, [key, elem]) => executeFunction(fn, [result, elem, key], contextStack, sourceCodeInfo), initial);
30200
30807
  }
30201
30808
  },
30202
30809
  arity: toFixedArity(3),
@@ -30232,23 +30839,17 @@ cu.update-in(
30232
30839
  if (typeof coll === 'string') {
30233
30840
  if (coll.length === 0)
30234
30841
  return initial;
30235
- return coll.split('').reduceRight((result, elem) => {
30236
- return executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
30237
- }, initial);
30842
+ return reduceSequential(Array.from(coll.split('')).reverse(), (result, elem) => executeFunction(fn, [result, elem], contextStack, sourceCodeInfo), initial);
30238
30843
  }
30239
30844
  else if (Array.isArray(coll)) {
30240
30845
  if (coll.length === 0)
30241
30846
  return initial;
30242
- return coll.reduceRight((result, elem) => {
30243
- return executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
30244
- }, initial);
30847
+ return reduceSequential(Array.from(coll).reverse(), (result, elem) => executeFunction(fn, [result, elem], contextStack, sourceCodeInfo), initial);
30245
30848
  }
30246
30849
  else {
30247
30850
  if (Object.keys(coll).length === 0)
30248
30851
  return initial;
30249
- return Object.entries(coll).reduceRight((result, [, elem]) => {
30250
- return executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
30251
- }, initial);
30852
+ return reduceSequential(Object.entries(coll).reverse(), (result, [, elem]) => executeFunction(fn, [result, elem], contextStack, sourceCodeInfo), initial);
30252
30853
  }
30253
30854
  },
30254
30855
  arity: toFixedArity(3),
@@ -30277,23 +30878,17 @@ cu.update-in(
30277
30878
  if (typeof coll === 'string') {
30278
30879
  if (coll.length === 0)
30279
30880
  return initial;
30280
- return coll.split('').reduceRight((result, elem, index) => {
30281
- return executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo);
30282
- }, initial);
30881
+ return reduceSequential(Array.from(coll.split('')).reverse().map((elem, _, arr) => ({ elem, index: arr.length - 1 - _ })), (result, { elem, index }) => executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo), initial);
30283
30882
  }
30284
30883
  else if (Array.isArray(coll)) {
30285
30884
  if (coll.length === 0)
30286
30885
  return initial;
30287
- return coll.reduceRight((result, elem, index) => {
30288
- return executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo);
30289
- }, initial);
30886
+ return reduceSequential(Array.from(coll).reverse().map((elem, _, arr) => ({ elem, index: arr.length - 1 - _ })), (result, { elem, index }) => executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo), initial);
30290
30887
  }
30291
30888
  else {
30292
30889
  if (Object.keys(coll).length === 0)
30293
30890
  return initial;
30294
- return Object.entries(coll).reduceRight((result, [key, elem]) => {
30295
- return executeFunction(fn, [result, elem, key], contextStack, sourceCodeInfo);
30296
- }, initial);
30891
+ return reduceSequential(Object.entries(coll).reverse(), (result, [key, elem]) => executeFunction(fn, [result, elem, key], contextStack, sourceCodeInfo), initial);
30297
30892
  }
30298
30893
  },
30299
30894
  arity: toFixedArity(3),
@@ -30327,40 +30922,20 @@ cu.update-in(
30327
30922
  assertFunctionLike(fn, sourceCodeInfo);
30328
30923
  assertAny(initial, sourceCodeInfo);
30329
30924
  assertAny(initial, sourceCodeInfo);
30330
- if (typeof coll === 'string') {
30331
- assertString(initial, sourceCodeInfo);
30332
- if (coll.length === 0)
30333
- return [initial];
30334
- const resultArray = [initial];
30335
- coll.split('').reduce((result, elem) => {
30336
- const newVal = executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
30925
+ const items = typeof coll === 'string'
30926
+ ? (assertString(initial, sourceCodeInfo), coll.length === 0 ? [] : coll.split(''))
30927
+ : Array.isArray(coll)
30928
+ ? (coll.length === 0 ? [] : Array.from(coll))
30929
+ : (Object.keys(coll).length === 0 ? [] : Object.entries(coll).map(([, v]) => v));
30930
+ if (items.length === 0)
30931
+ return [initial];
30932
+ const resultArray = [initial];
30933
+ return chain(reduceSequential(items, (result, elem) => {
30934
+ return chain(executeFunction(fn, [result, elem], contextStack, sourceCodeInfo), (newVal) => {
30337
30935
  resultArray.push(newVal);
30338
30936
  return newVal;
30339
- }, initial);
30340
- return resultArray;
30341
- }
30342
- else if (Array.isArray(coll)) {
30343
- if (coll.length === 0)
30344
- return [initial];
30345
- const resultArray = [initial];
30346
- coll.reduce((result, elem) => {
30347
- const newVal = executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
30348
- resultArray.push(newVal);
30349
- return newVal;
30350
- }, initial);
30351
- return resultArray;
30352
- }
30353
- else {
30354
- if (Object.keys(coll).length === 0)
30355
- return [initial];
30356
- const resultArray = [initial];
30357
- Object.entries(coll).reduce((result, [, elem]) => {
30358
- const newVal = executeFunction(fn, [result, elem], contextStack, sourceCodeInfo);
30359
- resultArray.push(newVal);
30360
- return newVal;
30361
- }, initial);
30362
- return resultArray;
30363
- }
30937
+ });
30938
+ }, initial), () => resultArray);
30364
30939
  },
30365
30940
  arity: toFixedArity(3),
30366
30941
  docs: {
@@ -30395,40 +30970,21 @@ cu.reductions(
30395
30970
  assertFunctionLike(fn, sourceCodeInfo);
30396
30971
  assertAny(initial, sourceCodeInfo);
30397
30972
  assertAny(initial, sourceCodeInfo);
30398
- if (typeof coll === 'string') {
30399
- assertString(initial, sourceCodeInfo);
30400
- if (coll.length === 0)
30401
- return [initial];
30402
- const resultArray = [initial];
30403
- coll.split('').reduce((result, elem, index) => {
30404
- const newVal = executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo);
30973
+ const toIndexedItem = (elem, key) => ({ elem, key });
30974
+ const items = typeof coll === 'string'
30975
+ ? (assertString(initial, sourceCodeInfo), coll.length === 0 ? [] : coll.split('').map((elem, index) => toIndexedItem(elem, index)))
30976
+ : Array.isArray(coll)
30977
+ ? (coll.length === 0 ? [] : coll.map((elem, index) => toIndexedItem(elem, index)))
30978
+ : (Object.keys(coll).length === 0 ? [] : Object.entries(coll).map(([key, v]) => toIndexedItem(v, key)));
30979
+ if (items.length === 0)
30980
+ return [initial];
30981
+ const resultArray = [initial];
30982
+ return chain(reduceSequential(items, (result, { elem, key }) => {
30983
+ return chain(executeFunction(fn, [result, elem, key], contextStack, sourceCodeInfo), (newVal) => {
30405
30984
  resultArray.push(newVal);
30406
30985
  return newVal;
30407
- }, initial);
30408
- return resultArray;
30409
- }
30410
- else if (Array.isArray(coll)) {
30411
- if (coll.length === 0)
30412
- return [initial];
30413
- const resultArray = [initial];
30414
- coll.reduce((result, elem, index) => {
30415
- const newVal = executeFunction(fn, [result, elem, index], contextStack, sourceCodeInfo);
30416
- resultArray.push(newVal);
30417
- return newVal;
30418
- }, initial);
30419
- return resultArray;
30420
- }
30421
- else {
30422
- if (Object.keys(coll).length === 0)
30423
- return [initial];
30424
- const resultArray = [initial];
30425
- Object.entries(coll).reduce((result, [key, elem]) => {
30426
- const newVal = executeFunction(fn, [result, elem, key], contextStack, sourceCodeInfo);
30427
- resultArray.push(newVal);
30428
- return newVal;
30429
- }, initial);
30430
- return resultArray;
30431
- }
30986
+ });
30987
+ }, initial), () => resultArray);
30432
30988
  },
30433
30989
  arity: toFixedArity(3),
30434
30990
  docs: {
@@ -30491,11 +31047,12 @@ cu.reductions(
30491
31047
  evaluate: ([coll, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
30492
31048
  assertColl(coll, sourceCodeInfo);
30493
31049
  assertFunctionLike(fn, sourceCodeInfo);
30494
- if (Array.isArray(coll))
30495
- return coll.every(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30496
- if (typeof coll === 'string')
30497
- return coll.split('').every(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30498
- return Object.entries(coll).every(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
31050
+ const arr = Array.isArray(coll)
31051
+ ? coll
31052
+ : typeof coll === 'string'
31053
+ ? coll.split('')
31054
+ : Object.entries(coll);
31055
+ return everySequential(arr, elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30499
31056
  },
30500
31057
  arity: toFixedArity(2),
30501
31058
  docs: {
@@ -30545,11 +31102,12 @@ cu.every?(
30545
31102
  evaluate: ([coll, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
30546
31103
  assertFunctionLike(fn, sourceCodeInfo);
30547
31104
  assertColl(coll, sourceCodeInfo);
30548
- if (Array.isArray(coll))
30549
- return coll.some(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30550
- if (typeof coll === 'string')
30551
- return coll.split('').some(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30552
- return Object.entries(coll).some(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
31105
+ const arr = Array.isArray(coll)
31106
+ ? coll
31107
+ : typeof coll === 'string'
31108
+ ? coll.split('')
31109
+ : Object.entries(coll);
31110
+ return someSequential(arr, elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30553
31111
  },
30554
31112
  arity: toFixedArity(2),
30555
31113
  docs: {
@@ -30597,11 +31155,12 @@ cu.any?(
30597
31155
  evaluate: ([coll, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
30598
31156
  assertFunctionLike(fn, sourceCodeInfo);
30599
31157
  assertColl(coll, sourceCodeInfo);
30600
- if (Array.isArray(coll))
30601
- return !coll.some(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30602
- if (typeof coll === 'string')
30603
- return !coll.split('').some(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30604
- return !Object.entries(coll).some(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
31158
+ const arr = Array.isArray(coll)
31159
+ ? coll
31160
+ : typeof coll === 'string'
31161
+ ? coll.split('')
31162
+ : Object.entries(coll);
31163
+ return chain(someSequential(arr, elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo)), result => !result);
30605
31164
  },
30606
31165
  arity: toFixedArity(2),
30607
31166
  docs: {
@@ -30649,11 +31208,12 @@ cu.not-any?(
30649
31208
  evaluate: ([coll, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
30650
31209
  assertFunctionLike(fn, sourceCodeInfo);
30651
31210
  assertColl(coll, sourceCodeInfo);
30652
- if (Array.isArray(coll))
30653
- return !coll.every(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30654
- if (typeof coll === 'string')
30655
- return !coll.split('').every(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30656
- return !Object.entries(coll).every(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
31211
+ const arr = Array.isArray(coll)
31212
+ ? coll
31213
+ : typeof coll === 'string'
31214
+ ? coll.split('')
31215
+ : Object.entries(coll);
31216
+ return chain(everySequential(arr, elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo)), result => !result);
30657
31217
  },
30658
31218
  arity: toFixedArity(2),
30659
31219
  docs: {
@@ -30710,14 +31270,8 @@ const sequenceUtilsFunctions = {
30710
31270
  if (seq === null)
30711
31271
  return null;
30712
31272
  assertSeq(seq, sourceCodeInfo);
30713
- if (typeof seq === 'string') {
30714
- const index = seq.split('').findIndex(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30715
- return index !== -1 ? index : null;
30716
- }
30717
- else {
30718
- const index = seq.findIndex(elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo));
30719
- return index !== -1 ? index : null;
30720
- }
31273
+ const arr = typeof seq === 'string' ? seq.split('') : seq;
31274
+ return chain(findIndexSequential(arr, elem => executeFunction(fn, [elem], contextStack, sourceCodeInfo)), index => index !== -1 ? index : null);
30721
31275
  },
30722
31276
  arity: toFixedArity(2),
30723
31277
  docs: {
@@ -30864,50 +31418,39 @@ su.position(
30864
31418
  assertSeq(seq, sourceCodeInfo);
30865
31419
  assertFunctionLike(keyfn, sourceCodeInfo);
30866
31420
  const comparer = defaultComparer ? null : params[2];
30867
- if (typeof seq === 'string') {
30868
- const result = seq.split('');
31421
+ const isString = typeof seq === 'string';
31422
+ const arr = isString ? seq.split('') : [...seq];
31423
+ // Pre-compute all keys using mapSequential (async-safe)
31424
+ return chain(mapSequential(arr, elem => executeFunction(keyfn, [elem], contextStack, sourceCodeInfo)), (keys) => {
30869
31425
  if (defaultComparer) {
30870
- result.sort((a, b) => {
30871
- const aKey = executeFunction(keyfn, [a], contextStack, sourceCodeInfo);
30872
- assertStringOrNumber(aKey, sourceCodeInfo);
30873
- const bKey = executeFunction(keyfn, [b], contextStack, sourceCodeInfo);
30874
- assertStringOrNumber(bKey, sourceCodeInfo);
30875
- return compare(aKey, bKey, sourceCodeInfo);
31426
+ // Create indexed pairs, sort by pre-computed keys
31427
+ const indexed = arr.map((elem, i) => ({ elem, key: keys[i] }));
31428
+ indexed.sort((a, b) => {
31429
+ assertStringOrNumber(a.key, sourceCodeInfo);
31430
+ assertStringOrNumber(b.key, sourceCodeInfo);
31431
+ return compare(a.key, b.key, sourceCodeInfo);
30876
31432
  });
31433
+ const sorted = indexed.map(x => x.elem);
31434
+ return isString ? sorted.join('') : sorted;
30877
31435
  }
30878
31436
  else {
30879
31437
  assertFunctionLike(comparer, sourceCodeInfo);
30880
- result.sort((a, b) => {
30881
- const aKey = executeFunction(keyfn, [a], contextStack, sourceCodeInfo);
30882
- const bKey = executeFunction(keyfn, [b], contextStack, sourceCodeInfo);
30883
- const compareValue = executeFunction(comparer, [aKey, bKey], contextStack, sourceCodeInfo);
31438
+ // Pre-compute keys, then need pairwise comparisons — these may also be async
31439
+ // For sort-by with custom comparer, we must use a non-async sort since
31440
+ // Array.sort requires sync comparators
31441
+ const indexed = arr.map((elem, i) => ({ elem, key: keys[i] }));
31442
+ indexed.sort((a, b) => {
31443
+ const compareValue = executeFunction(comparer, [a.key, b.key], contextStack, sourceCodeInfo);
31444
+ if (compareValue instanceof Promise) {
31445
+ throw new TypeError('Async functions cannot be used as sort-by comparators');
31446
+ }
30884
31447
  assertNumber(compareValue, sourceCodeInfo, { finite: true });
30885
31448
  return compareValue;
30886
31449
  });
31450
+ const sorted = indexed.map(x => x.elem);
31451
+ return isString ? sorted.join('') : sorted;
30887
31452
  }
30888
- return result.join('');
30889
- }
30890
- const result = [...seq];
30891
- if (defaultComparer) {
30892
- result.sort((a, b) => {
30893
- const aKey = executeFunction(keyfn, [a], contextStack, sourceCodeInfo);
30894
- assertStringOrNumber(aKey, sourceCodeInfo);
30895
- const bKey = executeFunction(keyfn, [b], contextStack, sourceCodeInfo);
30896
- assertStringOrNumber(bKey, sourceCodeInfo);
30897
- return compare(aKey, bKey, sourceCodeInfo);
30898
- });
30899
- }
30900
- else {
30901
- assertFunctionLike(comparer, sourceCodeInfo);
30902
- result.sort((a, b) => {
30903
- const aKey = executeFunction(keyfn, [a], contextStack, sourceCodeInfo);
30904
- const bKey = executeFunction(keyfn, [b], contextStack, sourceCodeInfo);
30905
- const compareValue = executeFunction(comparer, [aKey, bKey], contextStack, sourceCodeInfo);
30906
- assertNumber(compareValue, sourceCodeInfo, { finite: true });
30907
- return compareValue;
30908
- });
30909
- }
30910
- return result;
31453
+ });
30911
31454
  },
30912
31455
  arity: { min: 2, max: 3 },
30913
31456
  docs: {
@@ -30933,202 +31476,6 @@ su.position(
30933
31476
  ],
30934
31477
  },
30935
31478
  },
30936
- 'take': {
30937
- evaluate: ([input, n], sourceCodeInfo) => {
30938
- assertNumber(n, sourceCodeInfo);
30939
- assertSeq(input, sourceCodeInfo);
30940
- const num = Math.max(Math.ceil(n), 0);
30941
- return input.slice(0, num);
30942
- },
30943
- arity: toFixedArity(2),
30944
- docs: {
30945
- category: 'sequence',
30946
- returns: { type: 'sequence' },
30947
- args: {
30948
- a: { type: 'sequence' },
30949
- b: { type: 'integer' },
30950
- n: { type: 'integer' },
30951
- seq: { type: 'sequence' },
30952
- },
30953
- variants: [{ argumentNames: ['seq', 'n'] }],
30954
- description: 'Constructs a new array/string with the $n first elements from $seq.',
30955
- seeAlso: ['sequence.take-last', 'sequence.take-while', 'sequence.drop', 'slice', 'sequence.split-at'],
30956
- examples: [
30957
- 'let su = import("sequence"); su.take([1, 2, 3, 4, 5], 3)',
30958
- 'let su = import("sequence"); su.take([1, 2, 3, 4, 5], 3)',
30959
- 'let su = import("sequence"); su.take([1, 2, 3, 4, 5], 0)',
30960
- 'let su = import("sequence"); su.take("Albert", 2)',
30961
- 'let su = import("sequence"); su.take("Albert", 50)',
30962
- ],
30963
- },
30964
- },
30965
- 'take-last': {
30966
- evaluate: ([array, n], sourceCodeInfo) => {
30967
- assertSeq(array, sourceCodeInfo);
30968
- assertNumber(n, sourceCodeInfo);
30969
- const num = Math.max(Math.ceil(n), 0);
30970
- const from = array.length - num;
30971
- return array.slice(from);
30972
- },
30973
- arity: toFixedArity(2),
30974
- docs: {
30975
- category: 'sequence',
30976
- returns: { type: 'sequence' },
30977
- args: {
30978
- a: { type: 'sequence' },
30979
- b: { type: 'integer' },
30980
- n: { type: 'integer' },
30981
- seq: { type: 'sequence' },
30982
- },
30983
- variants: [{ argumentNames: ['n', 'seq'] }],
30984
- description: 'Constructs a new array with the $n last elements from $seq.',
30985
- seeAlso: ['sequence.take', 'sequence.drop-last'],
30986
- examples: [
30987
- 'let su = import("sequence"); su.take-last([1, 2, 3, 4, 5], 3)',
30988
- 'let su = import("sequence"); su.take-last([1, 2, 3, 4, 5], 3)',
30989
- 'let su = import("sequence"); su.take-last([1, 2, 3, 4, 5], 0)',
30990
- ],
30991
- },
30992
- },
30993
- 'take-while': {
30994
- evaluate: ([seq, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
30995
- assertSeq(seq, sourceCodeInfo);
30996
- assertFunctionLike(fn, sourceCodeInfo);
30997
- const result = [];
30998
- for (const item of seq) {
30999
- if (executeFunction(fn, [item], contextStack, sourceCodeInfo))
31000
- result.push(item);
31001
- else
31002
- break;
31003
- }
31004
- return typeof seq === 'string' ? result.join('') : result;
31005
- },
31006
- arity: toFixedArity(2),
31007
- docs: {
31008
- category: 'sequence',
31009
- returns: { type: 'sequence' },
31010
- args: {
31011
- a: { type: 'sequence' },
31012
- b: { type: 'function' },
31013
- seq: { type: 'sequence' },
31014
- fun: { type: 'function' },
31015
- },
31016
- variants: [{ argumentNames: ['seq', 'fun'] }],
31017
- description: 'Returns the members of $seq in order, stopping before the first one for which `predicate` returns a falsy value.',
31018
- seeAlso: ['sequence.take', 'sequence.drop-while', 'sequence.split-with'],
31019
- examples: [
31020
- `
31021
- let su = import("sequence");
31022
- su.take-while(
31023
- [1, 2, 3, 2, 1],
31024
- -> $ < 3
31025
- )`,
31026
- `
31027
- let su = import("sequence");
31028
- su.take-while(
31029
- [1, 2, 3, 2, 1],
31030
- -> $ > 3
31031
- )`,
31032
- ],
31033
- },
31034
- },
31035
- 'drop': {
31036
- evaluate: ([input, n], sourceCodeInfo) => {
31037
- assertNumber(n, sourceCodeInfo);
31038
- const num = Math.max(Math.ceil(n), 0);
31039
- assertSeq(input, sourceCodeInfo);
31040
- return input.slice(num);
31041
- },
31042
- arity: toFixedArity(2),
31043
- docs: {
31044
- category: 'sequence',
31045
- returns: { type: 'sequence' },
31046
- args: {
31047
- a: { type: 'sequence' },
31048
- b: { type: 'integer' },
31049
- seq: { type: 'sequence' },
31050
- n: { type: 'integer' },
31051
- },
31052
- variants: [{ argumentNames: ['seq', 'n'] }],
31053
- description: 'Constructs a new array/string with the $n first elements dropped from $seq.',
31054
- seeAlso: ['sequence.drop-last', 'sequence.drop-while', 'sequence.take', 'slice', 'sequence.split-at'],
31055
- examples: [
31056
- 'let su = import("sequence"); su.drop([1, 2, 3, 4, 5], 3)',
31057
- 'let su = import("sequence"); su.drop([1, 2, 3, 4, 5], 0)',
31058
- 'let su = import("sequence"); su.drop("Albert", 2)',
31059
- 'let su = import("sequence"); su.drop("Albert", 50)',
31060
- ],
31061
- },
31062
- },
31063
- 'drop-last': {
31064
- evaluate: ([array, n], sourceCodeInfo) => {
31065
- assertSeq(array, sourceCodeInfo);
31066
- assertNumber(n, sourceCodeInfo);
31067
- const num = Math.max(Math.ceil(n), 0);
31068
- const from = array.length - num;
31069
- return array.slice(0, from);
31070
- },
31071
- arity: toFixedArity(2),
31072
- docs: {
31073
- category: 'sequence',
31074
- returns: { type: 'sequence' },
31075
- args: {
31076
- a: { type: 'sequence' },
31077
- b: { type: 'integer' },
31078
- seq: { type: 'sequence' },
31079
- n: { type: 'integer' },
31080
- },
31081
- variants: [{ argumentNames: ['seq', 'n'] }],
31082
- description: 'Constructs a new array with the $n last elements dropped from $seq.',
31083
- seeAlso: ['sequence.drop', 'sequence.take-last'],
31084
- examples: [
31085
- 'let su = import("sequence"); su.drop-last([1, 2, 3, 4, 5], 3)',
31086
- 'let su = import("sequence"); su.drop-last([1, 2, 3, 4, 5], 3)',
31087
- 'let su = import("sequence"); su.drop-last([1, 2, 3, 4, 5], 0)',
31088
- ],
31089
- },
31090
- },
31091
- 'drop-while': {
31092
- evaluate: ([seq, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
31093
- assertSeq(seq, sourceCodeInfo);
31094
- assertFunctionLike(fn, sourceCodeInfo);
31095
- if (Array.isArray(seq)) {
31096
- const from = seq.findIndex(elem => !executeFunction(fn, [elem], contextStack, sourceCodeInfo));
31097
- return seq.slice(from);
31098
- }
31099
- const charArray = seq.split('');
31100
- const from = charArray.findIndex(elem => !executeFunction(fn, [elem], contextStack, sourceCodeInfo));
31101
- return charArray.slice(from).join('');
31102
- },
31103
- arity: toFixedArity(2),
31104
- docs: {
31105
- category: 'sequence',
31106
- returns: { type: 'sequence' },
31107
- args: {
31108
- a: { type: 'sequence' },
31109
- b: { type: 'function' },
31110
- seq: { type: 'sequence' },
31111
- fun: { type: 'function' },
31112
- },
31113
- variants: [{ argumentNames: ['seq', 'fun'] }],
31114
- description: 'Returns the members of $seq in order, skipping the fist elements for witch the `predicate` returns a truethy value.',
31115
- seeAlso: ['sequence.drop', 'sequence.take-while', 'sequence.split-with'],
31116
- examples: [
31117
- `
31118
- let su = import("sequence");
31119
- su.drop-while(
31120
- [1, 2, 3, 2, 1],
31121
- -> $ < 3
31122
- )`,
31123
- `
31124
- let su = import("sequence");
31125
- su.drop-while(
31126
- [1, 2, 3, 2, 1],
31127
- -> $ > 3
31128
- )`,
31129
- ],
31130
- },
31131
- },
31132
31479
  'unshift': {
31133
31480
  evaluate: ([seq, ...values], sourceCodeInfo) => {
31134
31481
  assertSeq(seq, sourceCodeInfo);
@@ -31201,12 +31548,8 @@ l`,
31201
31548
  evaluate: ([input, fn], sourceCodeInfo, contextStack, { executeFunction }) => {
31202
31549
  assertFunctionLike(fn, sourceCodeInfo);
31203
31550
  assertSeq(input, sourceCodeInfo);
31204
- if (Array.isArray(input))
31205
- return input.filter(elem => !executeFunction(fn, [elem], contextStack, sourceCodeInfo));
31206
- return input
31207
- .split('')
31208
- .filter(elem => !executeFunction(fn, [elem], contextStack, sourceCodeInfo))
31209
- .join('');
31551
+ const arr = Array.isArray(input) ? input : input.split('');
31552
+ return chain(filterSequential(arr, elem => chain(executeFunction(fn, [elem], contextStack, sourceCodeInfo), result => !result)), filtered => typeof input === 'string' ? filtered.join('') : filtered);
31210
31553
  },
31211
31554
  arity: toFixedArity(2),
31212
31555
  docs: {
@@ -31281,7 +31624,7 @@ l`,
31281
31624
  },
31282
31625
  variants: [{ argumentNames: ['seq', 'n'] }],
31283
31626
  description: 'Returns a pair of sequence `[take(pos input), drop(pos input)]`.',
31284
- seeAlso: ['sequence.split-with', 'sequence.take', 'sequence.drop'],
31627
+ seeAlso: ['sequence.split-with', 'take', 'drop'],
31285
31628
  examples: [
31286
31629
  'let su = import("sequence"); su.split-at([1, 2, 3, 4, 5], 2)',
31287
31630
  'let su = import("sequence"); su.split-at("Albert", -2)',
@@ -31296,10 +31639,11 @@ l`,
31296
31639
  assertSeq(seq, sourceCodeInfo);
31297
31640
  const seqIsArray = Array.isArray(seq);
31298
31641
  const arr = seqIsArray ? seq : seq.split('');
31299
- const index = arr.findIndex(elem => !executeFunction(fn, [elem], contextStack, sourceCodeInfo));
31300
- if (index === -1)
31301
- return [seq, seqIsArray ? [] : ''];
31302
- return [seq.slice(0, index), seq.slice(index)];
31642
+ return chain(findIndexSequential(arr, elem => chain(executeFunction(fn, [elem], contextStack, sourceCodeInfo), result => !result)), (index) => {
31643
+ if (index === -1)
31644
+ return [seq, seqIsArray ? [] : ''];
31645
+ return [seq.slice(0, index), seq.slice(index)];
31646
+ });
31303
31647
  },
31304
31648
  arity: toFixedArity(2),
31305
31649
  docs: {
@@ -31313,7 +31657,7 @@ l`,
31313
31657
  },
31314
31658
  variants: [{ argumentNames: ['seq', 'fun'] }],
31315
31659
  description: 'Returns a pair of sequences `[take-while(input, fun), drop-while(input, fun)]`.',
31316
- seeAlso: ['sequence.split-at', 'sequence.take-while', 'sequence.drop-while'],
31660
+ seeAlso: ['sequence.split-at', 'take-while', 'drop-while'],
31317
31661
  examples: [
31318
31662
  'let su = import("sequence"); su.split-with([1, 2, 3, 4, 5], odd?)',
31319
31663
  'let su = import("sequence"); su.split-with([1, 2, 3, 4, 5], -> $ > 3)',
@@ -31353,13 +31697,14 @@ l`,
31353
31697
  assertFunctionLike(fn, sourceCodeInfo);
31354
31698
  assertSeq(seq, sourceCodeInfo);
31355
31699
  const arr = Array.isArray(seq) ? seq : seq.split('');
31356
- return arr.reduce((result, val) => {
31357
- const key = executeFunction(fn, [val], contextStack, sourceCodeInfo);
31358
- assertString(key, sourceCodeInfo);
31359
- if (!collHasKey(result, key))
31360
- result[key] = [];
31361
- result[key].push(val);
31362
- return result;
31700
+ return reduceSequential(arr, (result, val) => {
31701
+ return chain(executeFunction(fn, [val], contextStack, sourceCodeInfo), (key) => {
31702
+ assertString(key, sourceCodeInfo);
31703
+ if (!collHasKey(result, key))
31704
+ result[key] = [];
31705
+ result[key].push(val);
31706
+ return result;
31707
+ });
31363
31708
  }, {});
31364
31709
  },
31365
31710
  arity: toFixedArity(2),
@@ -31468,17 +31813,17 @@ l`,
31468
31813
  assertFunctionLike(fn, sourceCodeInfo);
31469
31814
  assertSeq(seq, sourceCodeInfo);
31470
31815
  const isStringSeq = typeof seq === 'string';
31471
- let oldValue;
31472
- const result = (isStringSeq ? seq.split('') : seq).reduce((acc, elem) => {
31473
- const value = executeFunction(fn, [elem], contextStack, sourceCodeInfo);
31474
- if (value !== oldValue) {
31475
- acc.push([]);
31476
- oldValue = value;
31477
- }
31478
- acc[acc.length - 1].push(elem);
31479
- return acc;
31480
- }, []);
31481
- return isStringSeq ? result.map(elem => elem.join('')) : result;
31816
+ const arr = isStringSeq ? seq.split('') : seq;
31817
+ return chain(reduceSequential(arr, (acc, elem) => {
31818
+ return chain(executeFunction(fn, [elem], contextStack, sourceCodeInfo), (value) => {
31819
+ if (value !== acc.oldValue) {
31820
+ acc.result.push([]);
31821
+ acc.oldValue = value;
31822
+ }
31823
+ acc.result[acc.result.length - 1].push(elem);
31824
+ return acc;
31825
+ });
31826
+ }, { result: [], oldValue: undefined }), ({ result }) => isStringSeq ? result.map(elem => elem.join('')) : result);
31482
31827
  },
31483
31828
  arity: toFixedArity(2),
31484
31829
  docs: {
@@ -32734,6 +33079,12 @@ const api = {
32734
33079
  'next',
32735
33080
  'sort',
32736
33081
  'slice',
33082
+ 'take',
33083
+ 'take-last',
33084
+ 'drop',
33085
+ 'drop-last',
33086
+ 'take-while',
33087
+ 'drop-while',
32737
33088
  ],
32738
33089
  sequenceUtils: [
32739
33090
  'sequence.position',
@@ -32742,12 +33093,6 @@ const api = {
32742
33093
  'sequence.unshift',
32743
33094
  'sequence.splice',
32744
33095
  'sequence.sort-by',
32745
- 'sequence.take',
32746
- 'sequence.take-last',
32747
- 'sequence.take-while',
32748
- 'sequence.drop',
32749
- 'sequence.drop-last',
32750
- 'sequence.drop-while',
32751
33096
  'sequence.distinct',
32752
33097
  'sequence.remove',
32753
33098
  'sequence.remove-at',
@@ -32823,13 +33168,13 @@ const api = {
32823
33168
  'arity',
32824
33169
  ],
32825
33170
  misc: [
32826
- '',
33171
+ '!=',
32827
33172
  '==',
32828
33173
  '<',
32829
33174
  '>',
32830
33175
  '<=',
32831
33176
  '>=',
32832
- '!',
33177
+ 'not',
32833
33178
  'write!',
32834
33179
  'iso-date->epoch',
32835
33180
  'epoch->iso-date',