I wanted to combine two or more functions to produce a new function.
How can I create a function that performs left-to-right function compositions by returning a function that accepts one argument?
For example:
const square = v => v * v;
const double = v => v * 2;
const addOne = v => v + 1;
const cal = myFunction(square, double, addOne);
cal(2) // 9; addOne(double(square(2)))
You might have myFunction turn the passed functions into an array with rest parameters, and then return a function that iterates over the array with reduce, passing in the passed argument as the initial value:
const myFunction = (...fns) => arg => fns.reduce(
(a, fn) => fn(a),
arg
);
const square = v => v * v;
const double = v => v * 2;
const addOne = v => v + 1;
const cal = myFunction(square, double, addOne);
console.log(cal(2)) // 9; addOne(double(square(2)))
Related
Let's say I have a function called f that takes an integer argument called x and returns an integer. I also have an integer n that says how many times the function must call itself. So for example if my function call looks like this f(x) when n = 1, then it would look like this f(f(f(x))) when n = 3. How could something like that look in my example bellow:
function succ(n) {
return function (f, x) {
return f(x);
};
}
You could loop inside the inner function:
for(let i = 0; i < n; i++) x = f(x);
return x;
or alternatively let your function call itself:
return n > 0 ? succ(n - 1)(f, f(x)) : x;
We can express this algorithm corecursively. Corecursion builds its result on the way forward from the starting point:
const iterate = f => x =>
[x, () => iterate(f) (f(x))];
const main = iterate(x => x * 2) (1);
console.log(
main[1] () [1] () [1] () [1] () [1] () [1] () [1] () [1] () [0]); // 256
This is just a proof of concept but not what we actually want. How can we avoid the clunky interface? We can use a Proxy to make the non-argument function implicit. It is basically the same mechanism as with lazy property getters. Additionally we don't want to access values from the stream manually but with a function for convenience:
class ThunkProxy {
constructor(f) {
this.memo = undefined;
}
get(g, k) {
if (this.memo === undefined)
this.memo = g();
if (k === THUNK)
return true;
else if (k === Symbol.toPrimitive)
return () => this.memo;
else if (k === "valueOf")
return () => this.memo;
else return this.memo[k];
}
}
const THUNK = "thunk";
const thunk = f =>
new Proxy(f, new ThunkProxy(f));
const iterate = f => x =>
[x, thunk(() => iterate(f) (f(x)))];
const takeNth = n => ([head, tail]) =>
n === 0
? head
: takeNth(n - 1) (tail);
const main = iterate(x => x * 2) (1);
console.log(
main[1] [1] [1] [1] [1] [1] [1] [1] [0]); // 256
console.log(
takeNth(16) (main)); // 65536
You could build a times high order function and use it to wrap other functions...
const times = (fn, n) => (...args) => {
if (!n) { return; }
fn(...args);
return times(fn, n - 1)(...args);
}
const log10 = times(console.log, 10);
log10('hello');
I am implementing compose function using reduceRight menthod as follows
const compose = fns => (...args) =>
fns.reduceRight((acc, fn) => fn(acc, ...[args.slice(1)]), args[0]);
const func3 = (x, y) => (y > 0 ? x + 3 : x - 3);
const func2 = x => x ** 2;
const func1 = x => x - 8;
const fnOne = compose([func1, func2, func3])('3', 1);
console.log(fnOne); // should be 1081
const fnTwo = compose([func1, func2, func3])('3', -1);
console.log(fnTwo); //should be -8
the first function is supposed to receive two arguments and return the result to the next function as the only one argument. The problem is that the first function is passing two arguments to the next function instead of one. Let me know if you have any ideas how to fix it. Any help is very much appreciated.
The problem here is that you're not modifying the args variable.
Let's look at what happens in detail:
At the first call of your reductor, acc becomes func3(args[0], ...[args.shift(1)]) === func3(args[0], args[1], args[2], ...).
At the second call, acc becomes func2(acc, [args.shift(1)]), which is func2(func3(args[0], args[1], args[2], ...), args[1], args[2], ...).
You can already see where the problem lies: args1 is never dropped from the array, because Array.slice() creates a copy and does not modify the actual array.
To solve your problem you should instead use:
const compose = fns => (...args) =>
fns.reduceRight((acc, fn) => fn(acc, ...args.splice(0, fn.length - 1)), args[0]);
You need to call the first function outside the reduceRight() loop, since it's not being called the same way as all the other functions. It gets its arguments from ...args and its value should be used as the initial accumulator argument to reduce.
const compose = fns => (...args) => {
let last = fns.pop();
return fns.reduceRight((acc, fn) => fn(acc), last(...args))
};
const func3 = function(x, y) {
console.log(`func3 got ${arguments.length} arguments`);
return (y > 0 ? x + 3 : x - 3);
};
const func2 = function(x) {
console.log(`func2 got ${arguments.length} arguments`);
return x ** 2;
};
const func1 = function(x) {
console.log(`func2 got ${arguments.length} arguments`);
return x - 8;
};
const fnOne = compose([func1, func2, func3])('3', 1);
console.log(fnOne); // should be 1081
const fnTwo = compose([func1, func2, func3])('3', -1);
console.log(fnTwo); //should be -8
I am trying to implement function composition with multiple arguments using reduceRight. This question has been answered at this link but slightly with a different input data. For some reason I am getting the following error : Uncaught TypeError: fn is not a function. Avoid using func3 = ([x, y]) => (y > 0 ? x + 3 : x - 3); in this format. Let me know if there is a way to fix it.
const compose = (...fns) => (...args) =>
fns.reduceRight((acc, fn) => fn(acc), args);
const func3 = (x, y) => (y > 0 ? x + 3 : x - 3);
//const func3 = ([x, y]) => (y > 0 ? x + 3 : x - 3); - avoid using this version
const func2 = x => x ** 2;
const func1 = x => x - 8;
const fnOne = compose([func1, func2, func3])('3', 1);
console.log(fnOne); // should be 1081
const fnTwo = compose([func1, func2, func3])('3', -1);
console.log(fnTwo); //should be -8
[1]: https://stackoverflow.com/questions/55842990/multiple-arguments-composible-function-implementation-using-reduceright
SOLUTION
Array#reduceRight only has support for one currentValue so we can't have a function accept multiple arguments. The only way would be to avoid using reduceRight for the first call by popping it from the array and calling it manual instead of letting reduceRight do it:
First approach
const compose = fns => (...args) =>
fns.reduceRight((acc, fn) => fn(acc), fns.pop()(...args));
Second approach
const compose = fns => (...args) =>
fns.reduceRight((acc, fn) => fn(...[acc, ...args.slice(1)]), args[0]);
You're passing an array into compose instead of a function (or multiple functions), so fn is an array and you get that error when you try to use it as a function.
Either replace ...fns with fns (so that compose expects an array) or remove the square brackets in your calls to compose. Also use the version of func3 that you have commented out:
const compose = (...fns) => (...args) =>
fns.reduceRight((acc, fn) => fn(acc), args);
const func3 = ([x, y]) => (y > 0 ? x + 3 : x - 3);
const func2 = x => x ** 2;
const func1 = x => x - 8;
const fnOne = compose(func1, func2, func3)('3', 1);
console.log(fnOne); // should be 1081
const fnTwo = compose(func1, func2, func3)('3', -1);
console.log(fnTwo); //should be -8
If you don't can or want to convert func3 to a single argument function. You could spread the args when calling fn. Then capture the result in an array so it can be spread over the next fn call. When returning the final result simply take the first element of the resulting array.
const compose = (...fns) => (...args) =>
fns.reduceRight((args, fn) => [fn(...args)], args)[0];
const func3 = (x, y) => (y > 0 ? x + 3 : x - 3);
// const func3 = ([x, y]) => (y > 0 ? x + 3 : x - 3); - avoid using this version
const func2 = x => x ** 2;
const func1 = x => x - 8;
const fnOne = compose(func1, func2, func3)('3', 1);
console.log(fnOne); // should be 1081
const fnTwo = compose(func1, func2, func3)('3', -1);
console.log(fnTwo); //should be -8
You need provide to compose function three parameters/function instead a array.
func3 will be the first function performed, so it will receive the array args. This array need be destructure in x and y variable. This reduce can be make in the parameters definition, like this: ([x, y]).
const compose = (...fns) => (...args) =>
fns.reduceRight((acc, fn) => fn(acc), args);
const func3 = ([x, y]) => y > 0 ? x + 3 : x - 3;
const func2 = x => x ** 2;
const func1 = x => x - 8;
const fnOne = compose(func1, func2, func3)('3', 1);
console.log(fnOne); // should be 1081
const fnTwo = compose(func1, func2, func3)('3', -1);
console.log(fnTwo); //should be -8
As a toy example lets say we have this function and its usage:
const map = (f = n => n + 1) => (lst = [1,2,3]) => {
if(lst.length === 0)
return [];
else
return [f(...lst.splice(0,1)), ...map(f)(lst)];
}
const inc = n => n + 1;
const map_inc = map(inc);
map_inc([1,2,3]) // => (produces) [2,3,4]
Inside of the curried function map I am using "recursion" by calling map(f)(lst).
The example above rebuilds the function before it can be called.
Is it possible to do this recursion without rebuilding the function?
I know of this way:
y = (f = (f, ...args) => [...args],
...args) => f(f, ...args);
const map = (mapper = n => n + 1) => (self = mapper, lst = [1,2,3]) => {
if(lst.length === 0)
return [];
else
return [mapper(...lst.splice(0,1)), ...self(self, lst)];
}
const inc = n => n + 1;
const map_inc = (...args) => y(map(inc), ...args);
map_inc([1,2,3]) // => (produces) [2,3,4]
I do not really like how this requires the passing of the function to itself.
Can this be done without the y function and without passing the function to itself? Can this be done in a more point-free style?
If I'm understanding your question correctly, you can't return named arrow functions, but you can return a named regular function and call it recursively like this:
const reducer = k => function recurse(a, item) {
//...
const s_res = _.split(item, k, 1);
return recurse(a.withMutations(a => {
a.push(s_res[0]);
let a_element = document.createElement('a');
a_element.setAttribute('href', '#');
a_element.addEventListener('click', () => display_gen_element(k, obj));
a.push(a_element);
}), s_res[1]);
};
P.S. For the sake of readability please don't use one-letter variable names unless it's blindingly obvious what they're for, e.g. a counter in a for loop, etc.
If your purpose was remove the need to pass self to itself
...self(self, lst)
You can do this by adding 1 more function named recursor
const map = (mapper = n => n + 1) => (lst = [1, 2, 3]) => {
const recursor = lst => {
if (lst.length === 0) return [];
else return [mapper(...lst.splice(0, 1)), ...recursor(lst)];
};
return recursor(lst);
};
const inc = n => n + 1;
const map_inc = map(inc);
console.log(map_inc([1, 2, 3])); // => (produces) [2,3,4]
You didn't need the y combinator-like function called y at all.
recursor has mapper in its closure
In Haskell you can apply fmap to two functions, which is basically function composition. You can even compose fmap to enable function composition of functions with higher arity (fmap . fmap).
This works because functions are functors.
How would such a functor (or the appropriate map method) be implemented in Javascript?
This is what I have tried so far:
funcProto = {
map(f) { return y => f(this.x(y)) }
};
function func(x) {
return Object.assign(Object.create(funcProto), {x: x});
}
const comp = f => g => x => f(g(x));
const map = f => ftor => ftor.map(f);
const sub = y => x => x - y;
const sqr = x => x * x;
const inc = x => x + 1;
This works for normal function composition:
func(sqr).map(inc)(2); // 5
However, it doesn't work for a composed version of map:
const map2 = comp(map)(map);
map2(sub)(sub)(10)(5)(4); // Error
I think I adapt myself too much to the traditional way functors are implemented in Javascript. Functions as functors behave differently from list or maybe.
In Haskell, everything is a function. In your javascript, some of your functions are represented as funcs with an .x() method, and some are native Functions. That cannot work.
Here are three approaches:
const sub = y => x => x - y;
const sqr = x => x * x;
const inc = x => x + 1;
const comp = f => g => x => f(g(x));
plain functions, no methods.
const fmap = comp; // for functions only
console.log(fmap(inc)(sqr)(1)) // 5
const fmap2 = comp(fmap)(fmap);
console.log(fmap2(sub)(sub)(10)(5)(4)); // 9
extending native Functions, using fmap as a method:
Function.prototype.fmap = function(f) { return comp(this)(f); };
console.log(sqr.fmap(inc)(1)); // 5
const fmap2 = comp.fmap(comp) // not exactly what you want, works just like above
Function.prototype.fmap2 = function(f) { return this.fmap(g => g.fmap(f)); } // better
console.log(sub.fmap2(sub)(10)(5)(4)); // 9
building your own function type (also in ES6):
function Func(f) {
if (!new.target) return new Func(f);
this.call = f;
}
// Ahem.
const sub = Func(y => Func(x => x - y));
const sqr = Func(x => x * x);
const inc = Func(x => x + 1);
const comp = Func(f => Func(g => Func(x => f.call(g.call(x)))));
// Now let's start
const fmap = Func(f => Func(x => x.fmap(f))); // a typeclass!
Func.prototype.fmap = function(f) { return comp(this)(f); }; // an instance of the class!
console.log(fmap.call(inc).call(sqr).call(1)); // 5
const fmap2 = comp.call(fmap).call(fmap);
console.log(fmap2.call(sub).call(sub).call(10).call(5).call(4)); // 9
Forgive me if I'm mistaken but you seem to be confused about Functors in Haskell. The Functor type class in Haskell represents data types on which "map" (fmap to be more precise) is defined:
https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor.html
For instance, lists ([] in Haskell) are an instance of Functor, like:
fmap (\x->x+1) [1,2,3] -- returns [2,3,4]
As specified in the documentation above, it is true that fmap (f . g) should be equivalent to fmap f . fmap g (recall that . in Haskell means function composition, that is, (f.g) x equals f(g(x))). For instance, let
f x = x + 1
and:
g y = y * 2
Then
fmap (f.g) [1,2,3] -- equivalent to [(f.g) 1, (f.g) 2, (f.g) 3]
and
(fmap f . fmap g) [1,2,3] -- equivalent to (fmap f (fmap g [1,2,3]))
are equivalent and both return [3,5,7].
Arrays in JavaScript are already a Functor in this sense since they have map.
const f = x => x + 1;
const g = y => y * 2;
const comp = f => g => x => f(g(x));
const fmap_array = f => a => a.map(f);
fmap_array (comp(f)(g)) ([1,2,3]); // [3,5,7]
(comp (fmap_array(f)) (fmap_array(g))) ([1,2,3]); // [3,5,7]
Or, you can do this if you like:
Array.prototype.fmap = function(f) { return this.map(f); }
[1,2,3].fmap(f); // [2,3,4]
[1,2,3].fmap(g); // [2,4,6]
[1,2,3].fmap(comp(f)(g)); // [3,5,7]
[1,2,3].fmap(g).fmap(f); // [3,5,7]
P.S.
Now I see what you meant in your question - functions (-> in Haskell) are also an instance of Functor, indeed defined as function composition fmap f g = (f . g):
https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor.html#control.i:ic:Functor:Functor:28
https://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Base.html#line-638
For something similar in JavaScript,
const fmap_func = f => g => comp(f)(g); // or "const fmap_func = comp;"!
fmap_func(f)(g)(42); // 85
or, again if you like:
Function.prototype.fmap = function(f) { return comp(f)(this); };
g.fmap(f)(42); // 85