list.js (13040B)
1 import { REAmbiguous, REArgumentError, REOther } from "../errors/messages.js"; 2 import { makeDefinition } from "../library/registry/fnDefinition.js"; 3 import * as E_A_Floats from "../utility/E_A_Floats.js"; 4 import { frAny, frDist, frLambdaN, frArray, frNumber, frString, frTuple, frLambdaNand, } from "../library/registry/frTypes.js"; 5 import { FnFactory, doBinaryLambdaCall } from "../library/registry/helpers.js"; 6 import { vArray, vNumber, vString, vBool, uniq, uniqBy, } from "../value/index.js"; 7 import { sampleSetAssert } from "./sampleset.js"; 8 import { unzip, zip } from "../utility/E_A.js"; 9 export function _map(array, lambda, context, useIndex) { 10 const mapped = new Array(array.length); 11 if (!useIndex) { 12 for (let i = 0; i < array.length; i++) { 13 mapped[i] = lambda.call([array[i]], context); 14 } 15 } 16 else { 17 for (let i = 0; i < array.length; i++) { 18 mapped[i] = lambda.call([array[i], vNumber(i)], context); 19 } 20 } 21 return mapped; 22 } 23 export function _reduce(array, initialValue, lambda, context, useIndex) { 24 if (!useIndex) { 25 return array.reduce((acc, elem) => lambda.call([acc, elem], context), initialValue); 26 } 27 else { 28 return array.reduce((acc, elem, index) => lambda.call([acc, elem, vNumber(index)], context), initialValue); 29 } 30 } 31 export function _reduceWhile(array, initialValue, step, condition, context) { 32 let acc = initialValue; 33 for (let i = 0; i < array.length; i++) { 34 const newAcc = step.call([acc, array[i]], context); 35 const checkResult = condition.call([newAcc], context); 36 if (checkResult.type !== "Bool") { 37 throw new REArgumentError(`Condition should return a boolean value, got: ${checkResult.type}`); 38 } 39 if (!checkResult.value) { 40 return acc; 41 } 42 acc = newAcc; 43 } 44 return acc; 45 } 46 const _assertInteger = (number) => { 47 if (!Number.isInteger(number)) { 48 throw new REArgumentError(`Number ${number} must be an integer`); 49 } 50 }; 51 const _assertValidArrayLength = (number) => { 52 if (number < 0) { 53 throw new REArgumentError("Expected non-negative number"); 54 } 55 else if (!Number.isInteger(number)) { 56 throw new REArgumentError("Number must be an integer"); 57 } 58 }; 59 const _assertUnemptyArray = (array) => { 60 if (array.length === 0) { 61 throw new REArgumentError("List must not be empty"); 62 } 63 }; 64 function _binaryLambdaCheck1(lambda, context) { 65 return (el) => doBinaryLambdaCall([el], lambda, context); 66 } 67 const maker = new FnFactory({ 68 nameSpace: "List", 69 requiresNamespace: true, 70 }); 71 export const library = [ 72 maker.make({ 73 name: "make", 74 output: "Array", 75 examples: [ 76 `List.make(2, 3)`, 77 `List.make(2, {|| 3})`, 78 `List.make(2, {|f| f+1})`, 79 ], 80 definitions: [ 81 makeDefinition([frNumber, frLambdaNand([0, 1])], ([number, lambda]) => { 82 throw new REAmbiguous("Call with either 0 or 1 arguments, not both"); 83 }), 84 makeDefinition([frNumber, frLambdaN(0)], ([number, lambda], context) => { 85 _assertValidArrayLength(number); 86 return vArray(Array.from({ length: number }, (_) => lambda.call([], context))); 87 }), 88 makeDefinition([frNumber, frLambdaN(1)], ([number, lambda], context) => { 89 _assertValidArrayLength(number); 90 return vArray(Array.from({ length: number }, (_, i) => lambda.call([vNumber(i)], context))); 91 }), 92 makeDefinition([frNumber, frAny], ([number, value]) => { 93 _assertValidArrayLength(number); 94 return vArray(new Array(number).fill(value)); 95 }), 96 makeDefinition([frDist], ([dist]) => { 97 sampleSetAssert(dist); 98 return vArray(dist.samples.map(vNumber)); 99 }), 100 ], 101 }), 102 maker.make({ 103 name: "upTo", 104 output: "Array", 105 examples: [`List.upTo(1,4)`], 106 definitions: [ 107 makeDefinition([frNumber, frNumber], ([low, high]) => { 108 if (!Number.isInteger(low) || !Number.isInteger(high)) { 109 throw new REArgumentError("Low and high values must both be integers"); 110 } 111 return vArray(E_A_Floats.upTo(low, high).map(vNumber)); 112 }), 113 ], 114 }), 115 maker.make({ 116 name: "length", 117 requiresNamespace: true, 118 output: "Number", 119 examples: [`List.length([1,4,5])`], 120 definitions: [ 121 makeDefinition([frArray(frAny)], ([values]) => vNumber(values.length)), 122 ], 123 }), 124 maker.make({ 125 name: "first", 126 requiresNamespace: true, 127 examples: [`List.first([1,4,5])`], 128 definitions: [ 129 makeDefinition([frArray(frAny)], ([array]) => { 130 _assertUnemptyArray(array); 131 return array[0]; 132 }), 133 ], 134 }), 135 maker.make({ 136 name: "last", 137 requiresNamespace: true, 138 examples: [`List.last([1,4,5])`], 139 definitions: [ 140 makeDefinition([frArray(frAny)], ([array]) => { 141 _assertUnemptyArray(array); 142 return array[array.length - 1]; 143 }), 144 ], 145 }), 146 maker.make({ 147 name: "reverse", 148 output: "Array", 149 requiresNamespace: false, 150 examples: [`List.reverse([1,4,5])`], 151 definitions: [ 152 makeDefinition([frArray(frAny)], ([array]) => vArray([...array].reverse())), 153 ], 154 }), 155 maker.make({ 156 name: "map", 157 output: "Array", 158 requiresNamespace: false, 159 examples: [ 160 "List.map([1,4,5], {|x| x+1})", 161 "List.map([1,4,5], {|x,i| x+i+1})", 162 ], 163 definitions: [ 164 makeDefinition([frNumber, frLambdaNand([1, 2])], ([number, lambda]) => { 165 throw new REAmbiguous("Call with either 1 or 2 arguments, not both."); 166 }), 167 makeDefinition([frArray(frAny), frLambdaN(1)], ([array, lambda], context) => vArray(_map(array, lambda, context, false))), 168 makeDefinition([frArray(frAny), frLambdaN(2)], ([array, lambda], context) => vArray(_map(array, lambda, context, true))), 169 ], 170 }), 171 maker.make({ 172 name: "concat", 173 requiresNamespace: true, 174 examples: [`List.concat([1,2,3], [4, 5, 6])`], 175 definitions: [ 176 makeDefinition([frArray(frAny), frArray(frAny)], ([array1, array2]) => vArray([...array1].concat(array2))), 177 ], 178 }), 179 maker.make({ 180 name: "append", 181 requiresNamespace: true, 182 examples: [`List.append([1,4],5)`], 183 definitions: [ 184 makeDefinition([frArray(frAny), frAny], ([array, el]) => vArray([...array, el])), 185 ], 186 }), 187 maker.make({ 188 name: "slice", 189 requiresNamespace: true, 190 examples: [`List.slice([1,2,5,10],1,3)`], 191 definitions: [ 192 makeDefinition([frArray(frAny), frNumber], ([array, start]) => { 193 _assertInteger(start); 194 return vArray(array.slice(start)); 195 }), 196 makeDefinition([frArray(frAny), frNumber, frNumber], ([array, start, end]) => { 197 _assertInteger(start); 198 _assertInteger(end); 199 return vArray(array.slice(start, end)); 200 }), 201 ], 202 }), 203 maker.make({ 204 name: "uniq", 205 requiresNamespace: true, 206 examples: [`List.uniq([1,2,3,"hi",false,"hi"])`], 207 definitions: [ 208 makeDefinition([frArray(frAny)], ([arr]) => vArray(uniq(arr))), 209 ], 210 }), 211 maker.make({ 212 name: "uniqBy", 213 requiresNamespace: true, 214 examples: [`List.uniqBy([[1,5], [3,5], [5,7]], {|x| x[1]})`], 215 definitions: [ 216 makeDefinition([frArray(frAny), frLambdaN(1)], ([arr, lambda], context) => vArray(uniqBy(arr, (e) => lambda.call([e], context)))), 217 ], 218 }), 219 maker.make({ 220 name: "reduce", 221 requiresNamespace: false, 222 examples: [`List.reduce([1,4,5], 2, {|acc, el| acc+el})`], 223 definitions: [ 224 makeDefinition([frNumber, frLambdaNand([2, 3])], ([number, lambda]) => { 225 throw new REAmbiguous("Call with either 2 or 3 arguments, not both"); 226 }), 227 makeDefinition([frArray(frAny), frAny, frLambdaN(2)], ([array, initialValue, lambda], context) => _reduce(array, initialValue, lambda, context, false)), 228 makeDefinition([frArray(frAny), frAny, frLambdaN(3)], ([array, initialValue, lambda], context) => _reduce(array, initialValue, lambda, context, true)), 229 ], 230 }), 231 maker.make({ 232 name: "reduceReverse", 233 requiresNamespace: false, 234 examples: [`List.reduceReverse([1,4,5], 2, {|acc, el| acc-el})`], 235 definitions: [ 236 makeDefinition([frArray(frAny), frAny, frLambdaN(2)], ([array, initialValue, lambda], context) => _reduce([...array].reverse(), initialValue, lambda, context, false)), 237 ], 238 }), 239 maker.make({ 240 name: "reduceWhile", 241 requiresNamespace: true, 242 examples: [ 243 `List.reduceWhile([1,4,5], 0, {|acc, curr| acc + curr }, {|acc| acc < 5})`, 244 ], 245 definitions: [ 246 makeDefinition([frArray(frAny), frAny, frLambdaN(2), frLambdaN(1)], ([array, initialValue, step, condition], context) => _reduceWhile(array, initialValue, step, condition, context)), 247 ], 248 }), 249 maker.make({ 250 name: "filter", 251 requiresNamespace: false, 252 examples: [`List.filter([1,4,5], {|x| x>3})`], 253 definitions: [ 254 makeDefinition([frArray(frAny), frLambdaN(1)], ([array, lambda], context) => vArray(array.filter(_binaryLambdaCheck1(lambda, context)))), 255 ], 256 }), 257 maker.make({ 258 name: "every", 259 requiresNamespace: true, 260 examples: [`List.every([1,4,5], {|el| el>3 })`], 261 definitions: [ 262 makeDefinition([frArray(frAny), frLambdaN(1)], ([array, lambda], context) => vBool(array.every(_binaryLambdaCheck1(lambda, context)))), 263 ], 264 }), 265 maker.make({ 266 name: "some", 267 requiresNamespace: true, 268 examples: [`List.some([1,4,5], {|el| el>3 })`], 269 definitions: [ 270 makeDefinition([frArray(frAny), frLambdaN(1)], ([array, lambda], context) => vBool(array.some(_binaryLambdaCheck1(lambda, context)))), 271 ], 272 }), 273 maker.make({ 274 name: "find", 275 requiresNamespace: true, 276 examples: [`List.find([1,4,5], {|el| el>3 })`], 277 definitions: [ 278 makeDefinition([frArray(frAny), frLambdaN(1)], ([array, lambda], context) => { 279 const result = array.find(_binaryLambdaCheck1(lambda, context)); 280 if (!result) { 281 throw new REOther("No element found"); 282 } 283 return result; 284 }), 285 ], 286 }), 287 maker.make({ 288 name: "findIndex", 289 requiresNamespace: true, 290 examples: [`List.findIndex([1,4,5], {|el| el>3 })`], 291 definitions: [ 292 makeDefinition([frArray(frAny), frLambdaN(1)], ([array, lambda], context) => vNumber(array.findIndex(_binaryLambdaCheck1(lambda, context)))), 293 ], 294 }), 295 maker.make({ 296 name: "join", 297 requiresNamespace: true, 298 examples: [`List.join(["a", "b", "c"], ",")`], 299 definitions: [ 300 makeDefinition([frArray(frString), frString], ([array, joinStr]) => vString(array.join(joinStr))), 301 makeDefinition([frArray(frString)], ([array]) => vString(array.join())), 302 ], 303 }), 304 maker.make({ 305 name: "flatten", 306 requiresNamespace: true, 307 examples: [`List.flatten([[1,2], [3,4]])`], 308 definitions: [ 309 makeDefinition([frArray(frAny)], ([arr]) => vArray(arr).flatten()), 310 ], 311 }), 312 maker.make({ 313 name: "shuffle", 314 requiresNamespace: true, 315 examples: [`List.shuffle([1,3,4,20])`], 316 definitions: [ 317 makeDefinition([frArray(frAny)], ([arr]) => vArray(arr).shuffle()), 318 ], 319 }), 320 maker.make({ 321 name: "zip", 322 requiresNamespace: true, 323 examples: [`List.zip([1,3,4,20], [2,4,5,6])`], 324 definitions: [ 325 makeDefinition([frArray(frAny), frArray(frAny)], ([array1, array2]) => { 326 if (array1.length !== array2.length) { 327 throw new REArgumentError("List lengths must be equal"); 328 } 329 return vArray(zip(array1, array2).map((pair) => vArray(pair))); 330 }), 331 ], 332 }), 333 maker.make({ 334 name: "unzip", 335 requiresNamespace: true, 336 examples: [`List.unzip([[1,2], [2,3], [4,5]])`], 337 definitions: [ 338 makeDefinition([frArray(frTuple(frAny, frAny))], ([array]) => vArray(unzip(array).map((r) => vArray(r)))), 339 ], 340 }), 341 ]; 342 //# sourceMappingURL=list.js.map