In my previous Quesion:
Extracting data from a function chain without arrays
@Aadit M Shah gave me astonishing solution as follows:
https://mcmap.net/q/1782035/-extracting-data-from-a-function-chain-without-arrays
Given an expression like A(a)(b)(f)
where f
is a function, it's impossible to know whether f
is supposed to be added to the list or whether it's the reducing function. Hence, I'm going to describe how to write expressions like A(a)(b)(f, x)
which is equivalent to [a, b].reduce(f, x)
. This allows us to distinguish when the list ends depending upon how many arguments you provide:
const L = g => function (x, a) {
switch (arguments.length) {
case 1: return L(k => g((f, a) => k(f, f(a, x))));
case 2: return g((f, a) => a)(x, a);
}
};
const A = L(x => x);
const xs = A(1)(2)(3)(4)(5);
console.log(xs((x, y) => x + y, 0)); // 15
console.log(xs((x, y) => x * y, 1)); // 120
console.log(xs((a, x) => a.concat(x), [])); // [1,2,3,4,5]
It works due to continuations. Every time we add a new element, we accumulate a CPS function. Each CPS function calls the previous CPS function, thereby creating a CPS function chain. When we give this CPS function chain a base function, it unrolls the chain and allows us to reduce it. It's the same idea behind transducers and lenses.
There are 2 issues remained for me.
To distinguish reducing function, I consider some custom Typing mechanism using reflection, but in order to focus on this issue, so far I would like to simply apply
const isReducer = f => (typeof f === 'function');
Requirement to provide an initial value has a limit to fold/reduce, for instance, it's impossible to provide an initial value for binary operations to the reduce such as
const head = (a, b) => a; const tail = (a, b) => b;
(unless you provide the first/last value manually that makes no sense to run the code) In theory, every binary operations has a identity value, but something is impossible to provide as it is. The only way is to abstract as an identity.
Having said that, I can not refactor the provided code to single arguments and by a reducer type of the function, and the default value as the initial value of the sequence.
Can you provide the refactored code? Also any information of transducer/ CPS for this example is appreciated.
head
andtail
" - those are not valid binary operations toreduce
anyway, as their types do not fit. Please stop abusing function types as data structures and you'll see why. – Williwaw(a,b)=> a
or(a,b)=> b
IS binary operation. If you insist not, please give us some reference. – Calgaryreduce
, but head and tail is associative, therefore they are valid operators toreuduce
– Calgaryhead
andtail
are supposed to mean. Typically you would associate them with lists, where they have the typeslist<a> -> a
andlist<a> -> list<a>
, which are not binary operations at all. – Williwawhead = (a,b)=> a
andtail = (a,b)=> b
. In fact this is well-known binary operators of Monoids reducer. I will give you a sample in my answer here. – Antitrusthead
andlast
. When you saidtail
it confused both Bergi and me because the tail of a list is everything but the first element. – Detribalizelast
. – Antitrust