Consider the following implementation of take:
Instead of using an IIFE just use a normal function with a proper name to make things more explicit:
const _let = f =>
f();
const collateBy = f => xs =>
xs.reduce((m, x) =>
_let((r = f(x), ys = m.get(r) || []) =>
m.set(r, (ys.push(x), ys))), new Map());
const includes = t => s =>
s.includes(t);
xs = ["Dev", "Jeff", "Kalib", "Amy", "Gemma"];
const collation = collateBy(includes("e")) (xs);
console.log(collation.get(true));
console.log(collation.get(false));
In Lisp, a let expression is just syntactic sugar for a left-left lambda (i.e. an immediately-invoked function expression). For example, consider:
(let ([x 1]
[y 2])
(+ x y))
; This is syntactic sugar for:
((lambda (x y)
(+ x y))
1 2)
In ES6, we can use arrow functions and default parameters to create an IIFE that looks like a let expression as follows:
const z = ((x = 1, y = 2) => x + y)();
console.log(z);
Using this hack, we can define take
as follows:
const take = (n, xxs) =>
n === 0 || xxs.length === 0 ?
[] : (([x, ...xs] = xxs) => [x, ...take(n - 1, xs)])();
console.log(take(7, [1, 2, 3, 4, 5])); // [1, 2, 3, 4, 5]
console.log(take(3, [1, 2, 3, 4, 5])); // [1, 2, 3]
console.log(take(1, [undefined, 1])); // [undefined]
Hope that helps.