Skip to content

Commit d6871b4

Browse files
authored
Support array-first argument order for higher-order functions (#36)
* feat: Support array-first argument order for higher-order functions - map(array, fn) alongside map(fn, array) - filter(array, fn) alongside filter(fn, array) - fold/reduce(array, init, fn) alongside fold/reduce(fn, init, array) - find(array, fn) alongside find(fn, array) - some(array, fn) alongside some(fn, array) - every(array, fn) alongside every(fn, array) Function-first order still works for backwards compatibility. Updated documentation to only show array-first syntax. Updated language service documentation for autocompletions. * refactor: Address code review feedback - improve undefined check organization
1 parent c09c377 commit d6871b4

5 files changed

Lines changed: 464 additions & 154 deletions

File tree

docs/syntax.md

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,13 @@ Besides the "operator" functions, there are several pre-defined functions. You c
132132
| Function | Description |
133133
|:------------- |:----------- |
134134
| count(a) | Returns the number of items in an array. |
135-
| map(f, a) | Array map: Pass each element of `a` the function `f`, and return an array of the results. |
136-
| fold(f, y, a) | Array fold: Fold/reduce array `a` into a single value, `y` by setting `y = f(y, x, index)` for each element `x` of the array. |
137-
| reduce(f, y, a) | Alias for `fold`. Reduces array `a` into a single value using function `f` starting with accumulator `y`. |
138-
| filter(f, a) | Array filter: Return an array containing only the values from `a` where `f(x, index)` is `true`. |
139-
| find(f, a) | Returns the first element in array `a` where `f(x, index)` is `true`, or `undefined` if not found. |
140-
| some(f, a) | Returns `true` if at least one element in array `a` satisfies `f(x, index)`, `false` otherwise. |
141-
| every(f, a) | Returns `true` if all elements in array `a` satisfy `f(x, index)`. Returns `true` for empty arrays. |
135+
| map(a, f) | Array map: Pass each element of `a` to the function `f`, and return an array of the results. |
136+
| fold(a, y, f) | Array fold: Fold/reduce array `a` into a single value, `y` by setting `y = f(y, x, index)` for each element `x` of the array. |
137+
| reduce(a, y, f) | Alias for `fold`. Reduces array `a` into a single value using function `f` starting with accumulator `y`. |
138+
| filter(a, f) | Array filter: Return an array containing only the values from `a` where `f(x, index)` is `true`. |
139+
| find(a, f) | Returns the first element in array `a` where `f(x, index)` is `true`, or `undefined` if not found. |
140+
| some(a, f) | Returns `true` if at least one element in array `a` satisfies `f(x, index)`, `false` otherwise. |
141+
| every(a, f) | Returns `true` if all elements in array `a` satisfy `f(x, index)`. Returns `true` for empty arrays. |
142142
| unique(a) | Returns a new array with duplicate values removed from array `a`. |
143143
| distinct(a) | Alias for `unique`. Returns a new array with duplicate values removed. |
144144
| indexOf(x, a) | Return the first index of string or array `a` matching the value `x`, or `-1` if not found. |
@@ -359,14 +359,14 @@ factorial(x) = x < 2 ? 1 : x * factorial(x - 1)
359359
These functions can than be used in other functions that require a function argument, such as `map`, `filter` or `fold`:
360360

361361
```js
362-
name(u) = u.name; map(name, users)
363-
add(a, b) = a+b; fold(add, 0, [1, 2, 3])
362+
name(u) = u.name; map(users, name)
363+
add(a, b) = a+b; fold([1, 2, 3], 0, add)
364364
```
365365

366366
You can also define the functions inline:
367367

368368
```js
369-
filter(isEven(x) = x % 2 == 0, [1, 2, 3, 4, 5])
369+
filter([1, 2, 3, 4, 5], isEven(x) = x % 2 == 0)
370370
```
371371

372372
### Arrow Functions
@@ -376,18 +376,18 @@ Arrow functions provide a concise syntax for inline functions, similar to JavaSc
376376
**Single parameter (no parentheses required):**
377377

378378
```js
379-
map(x => x * 2, [1, 2, 3]) // [2, 4, 6]
380-
filter(x => x > 2, [1, 2, 3, 4]) // [3, 4]
381-
map(x => x.name, users) // Extract property from objects
379+
map([1, 2, 3], x => x * 2) // [2, 4, 6]
380+
filter([1, 2, 3, 4], x => x > 2) // [3, 4]
381+
map(users, x => x.name) // Extract property from objects
382382
```
383383

384384
**Multiple parameters (parentheses required):**
385385

386386
```js
387-
fold((acc, x) => acc + x, 0, [1, 2, 3, 4, 5]) // 15 (sum)
388-
fold((acc, x) => acc * x, 1, [1, 2, 3, 4, 5]) // 120 (product)
389-
map((val, idx) => val + idx, [10, 20, 30]) // [10, 21, 32]
390-
filter((x, i) => i >= 1, [10, 20, 30]) // [20, 30]
387+
fold([1, 2, 3, 4, 5], 0, (acc, x) => acc + x) // 15 (sum)
388+
fold([1, 2, 3, 4, 5], 1, (acc, x) => acc * x) // 120 (product)
389+
map([10, 20, 30], (val, idx) => val + idx) // [10, 21, 32]
390+
filter([10, 20, 30], (x, i) => i >= 1) // [20, 30]
391391
```
392392

393393
**Zero parameters:**
@@ -401,23 +401,23 @@ filter((x, i) => i >= 1, [10, 20, 30]) // [20, 30]
401401
Arrow functions can be assigned to variables for reuse:
402402

403403
```js
404-
fn = x => x * 2; map(fn, [1, 2, 3]) // [2, 4, 6]
405-
double = x => x * 2; triple = x => x * 3; map(double, map(triple, [1, 2])) // [6, 12]
404+
fn = x => x * 2; map([1, 2, 3], fn) // [2, 4, 6]
405+
double = x => x * 2; triple = x => x * 3; map(map([1, 2], triple), double) // [6, 12]
406406
```
407407

408408
**Nested arrow functions:**
409409

410410
```js
411-
map(row => map(x => x * 2, row), [[1, 2], [3, 4]]) // [[2, 4], [6, 8]]
411+
map([[1, 2], [3, 4]], row => map(row, x => x * 2)) // [[2, 4], [6, 8]]
412412
```
413413

414414
**With member access and complex expressions:**
415415

416416
```js
417-
filter(x => x.age > 25, users) // Filter objects by property
418-
map(x => x.value * 2 + 1, items) // Complex transformations
419-
filter(x => x > 0 and x < 10, numbers) // Using logical operators
420-
map(x => x > 5 ? "high" : "low", [3, 7, 2, 9]) // Using ternary operator
417+
filter(users, x => x.age > 25) // Filter objects by property
418+
map(items, x => x.value * 2 + 1) // Complex transformations
419+
filter(numbers, x => x > 0 and x < 10) // Using logical operators
420+
map([3, 7, 2, 9], x => x > 5 ? "high" : "low") // Using ternary operator
421421
```
422422

423423
> **Note:** Arrow functions share the same `fndef` operator flag as traditional function definitions. If function definitions are disabled via parser options, arrow functions will also be disabled.
@@ -429,25 +429,25 @@ The new array utility functions provide additional ways to work with arrays:
429429
**Using reduce (alias for fold):**
430430

431431
```js
432-
reduce((acc, x) => acc + x, 0, [1, 2, 3, 4]) // 10 (sum using reduce)
433-
reduce((acc, x) => acc * x, 1, [2, 3, 4]) // 24 (product)
432+
reduce([1, 2, 3, 4], 0, (acc, x) => acc + x) // 10 (sum using reduce)
433+
reduce([2, 3, 4], 1, (acc, x) => acc * x) // 24 (product)
434434
```
435435

436436
**Using find:**
437437

438438
```js
439-
find(x => x > 5, [1, 3, 7, 2, 9]) // 7 (first element > 5)
440-
find(x => x < 0, [1, 2, 3]) // undefined (not found)
441-
find(x => x.age > 18, users) // First user over 18
439+
find([1, 3, 7, 2, 9], x => x > 5) // 7 (first element > 5)
440+
find([1, 2, 3], x => x < 0) // undefined (not found)
441+
find(users, x => x.age > 18) // First user over 18
442442
```
443443

444444
**Using some and every:**
445445

446446
```js
447-
some(x => x > 10, [1, 5, 15, 3]) // true (at least one > 10)
448-
every(x => x > 0, [1, 2, 3, 4]) // true (all positive)
449-
every(x => x % 2 == 0, [2, 4, 5, 6]) // false (not all even)
450-
some(x => x < 0, [1, 2, 3]) // false (none negative)
447+
some([1, 5, 15, 3], x => x > 10) // true (at least one > 10)
448+
every([1, 2, 3, 4], x => x > 0) // true (all positive)
449+
every([2, 4, 5, 6], x => x % 2 == 0) // false (not all even)
450+
some([1, 2, 3], x => x < 0) // false (none negative)
451451
```
452452

453453
**Using unique/distinct:**
@@ -462,11 +462,11 @@ unique([]) // []
462462

463463
```js
464464
// Filter positive numbers, remove duplicates, then double each
465-
unique(filter(x => x > 0, [1, -2, 3, 3, -4, 5, 1])) // [1, 3, 5]
466-
map(x => x * 2, unique([1, 2, 2, 3])) // [2, 4, 6]
465+
unique(filter([1, -2, 3, 3, -4, 5, 1], x => x > 0)) // [1, 3, 5]
466+
map(unique([1, 2, 2, 3]), x => x * 2) // [2, 4, 6]
467467

468468
// Find first even number greater than 5
469-
find(x => x % 2 == 0, filter(x => x > 5, [3, 7, 8, 9, 10])) // 8
469+
find(filter([3, 7, 8, 9, 10], x => x > 5), x => x % 2 == 0) // 8
470470
```
471471

472472
### Examples of Type Checking Functions
@@ -497,29 +497,29 @@ if(isString(x), toUpper(x), x) // Uppercase if string
497497
**Using with filter:**
498498

499499
```js
500-
filter(isNumber, [1, "a", 2, "b", 3]) // [1, 2, 3]
501-
filter(isString, [1, "a", 2, "b", 3]) // ["a", "b"]
500+
filter([1, "a", 2, "b", 3], isNumber) // [1, 2, 3]
501+
filter([1, "a", 2, "b", 3], isString) // ["a", "b"]
502502
```
503503

504504
**Using with some/every:**
505505

506506
```js
507-
some(isString, [1, 2, "hello", 3]) // true (has at least one string)
508-
every(isNumber, [1, 2, 3, 4]) // true (all are numbers)
509-
every(isNumber, [1, "a", 3]) // false (not all numbers)
507+
some([1, 2, "hello", 3], isString) // true (has at least one string)
508+
every([1, 2, 3, 4], isNumber) // true (all are numbers)
509+
every([1, "a", 3], isNumber) // false (not all numbers)
510510
```
511511

512512
**Practical examples:**
513513

514514
```js
515515
// Count how many strings are in an array
516-
count(filter(isString, [1, "a", 2, "b", 3])) // 2
516+
count(filter([1, "a", 2, "b", 3], isString)) // 2
517517

518518
// Get the first number in a mixed array
519-
find(isNumber, ["a", "b", 3, "c", 5]) // 3
519+
find(["a", "b", 3, "c", 5], isNumber) // 3
520520

521521
// Check if any value is null or undefined
522-
some(x => isNull(x) or isUndefined(x), data) // true/false
522+
some(data, x => isNull(x) or isUndefined(x)) // true/false
523523
```
524524

525525
## Custom JavaScript Functions

0 commit comments

Comments
 (0)