Convert array to rest argument - javascript

How do I make chain use a spread-parameter (...chain) instead of an array?
let newData,
newArgs,
chain = function (data, myargs) {
if (myargs.length === 0) {
return;
}
newData = myargs[0](data);
myargs.splice(0, 1);
newArgs = myargs;
// newargs === array
chain(newData, newArgs);
},
add1 = (num) => {
return num + 1;
};
When I call the function, I have to do it like this: chain(5, [add1, add1, add1]).
But I want: chain(5, add1, add1, add1)
The problem is, that newArgs (the function parameter inside of the recursion) is converted into an array after the first function call.
https://jsfiddle.net/btx5sfwh/

You probably want to use rest arguments, then spread the array when calling the function recursively
let newData,
newArgs,
chain = (data, ...myargs) => {
if (myargs.length === 0) {
return data;
} else {
newData = myargs[0](data);
myargs.splice(0, 1);
newArgs = myargs;
chain(newData, ...newArgs);
}
},
add1 = (num) => {
return num + 1;
};
chain(5, add1, add1, add1);
console.log(newData); // 8

You can write chain in a much nicer way
const chain = (x, f, ...fs) =>
f === undefined
? x
: chain (f (x), ...fs)
const add1 = x =>
x + 1
console.log (chain (5, add1, add1, add1)) // 8
console.log (chain (5)) // 5
Rest parameter and spread arguments are somewhat expensive tho - we generally want to limit our dependency on these, but we don't want to sacrifice the API we want either.
Don't worry, there's an even higher-level way to think about this problem. We can preserve the variadic API but avoid the costly spread argument.
const chain = (x, ...fs) =>
fs.reduce((x, f) => f (x), x)
const add1 = x =>
x + 1
console.log (chain (5, add1, add1, add1)) // 8
console.log (chain (5)) // 5

Related

How to create a composition from functions

I have 5 functions: func1(), func2(), func3(), func4(), func5(). I need to implement the compositionFunc() function, which can take any number of functions as arguments, and create a composition from them. The compositionFunc() function takes my 5 functions as arguments. The compositionFunc() function returns a function that takes its initial value as an argument. This nested function successively passing through an array of functions with each iteration returns the result of calling the accumulated value of the current function-argument. The result of one function can be passed as an argument to another function. How can i do this?
const func1 = (arg1) => {
return arg1;
};
const func2 = (arg2) => {
return arg2;
};
const func3 = (arg3) => {
return arg3;
};
const func4 = (arg4) => {
return arg4;
};
const func5 = (arg5) => {
return arg5;
};
const compositionFunc = () => {
...
};
you can define a function like this
const pipe = (...functions) => args => functions.reduce((res, f) => f(res), args)
const combine = (...functions) => args => functions.reduceRight((res, f) => f(res), args)
const plus1 = x => x + 1
const double = x => x * 2
const pipeFunction = pipe(plus1, double)
const combineFunction = combine(plus1, double)
console.log(combineFunction(1)) // (1 * 2) + 1
console.log(pipeFunction(1)) // (1 + 1) * 2
A simple reduce can accomplish that:
function pipe(input, ...func) {
return func.reduce((a, f) => f(a), input);
}
You pass it an initial value + chain of functions.
Example:
function f1(val) {
return val + 1;
}
function f2(val) {
return val * 10;
}
console.log(pipe(2, f1, f2)); //=> 30

Chain methods and call function one by one

so basically I need to implement a lazy evaluation. .add() takes a function as parameter and any other arbitrary arguments. The function that is passed as an argument is run later (when evaluate is called) with other arguments(if any) as parameters to that function.
Basically my issue stands when i run .evaluate() which takes an array as parameter, the functions that were passed to add() as parameters are not called one at a time and returning a result and have it as a parameter for the next.
class Lazy {
constructor() {
this.functions = [];
this.counter = 0;
this.resultedArray = [];
}
add(func, ...args) {
if (args.length > 0) {
this.counter++;
const argsArrayNumeric = args.filter((item) => typeof item === "number");
this.functions.push({
func: func,
args: args,
});
} else {
if (func.length <= args.length + 1 || func.length === args.length) {
this.counter++;
this.functions.push({ func: func });
} else {
console.log("Missing parameters for " + func.name + " function");
}
}
return this;
}
evaluate(array) {
if (this.counter > 0) {
let result;
this.functions.map((obj, index) => {
array.map((item, index) => {
console.log(obj);
if (obj.func && obj.args) {
result = obj.func(item, ...obj.args);
} else {
result = obj.func(item);
}
this.resultedArray.push(result);
});
});
console.log(this.resultedArray);
} else {
console.log(array);
}
}
}
const s = new Lazy();
const timesTwo = (a) => {
return a * 2;
};
const plus = (a, b) => {
return a + b;
};
s.add(timesTwo).add(plus, 1).evaluate([1, 2, 3]);
//correct result is [3,5,7] but i have [ 2, 4, 6, 2, 3, 4 ]
There are a few problems in evaluate:
push will be executed too many times when you have more than one function.
Don't use map when you don't really map. .map() returns a result.
From the expected output (in the original version of the question) it seems you need to apply the functions from right to left, not from left to right.
this.counter does not really play a role. The length of the this.functions array should be all you need.
the result should not be printed in the method, but returned. It is the caller's responsibility to print it or do something else with it.
All this can be dealt with using reduce or reduceRight (depending on the expected order) like this:
evaluate(array) {
return this.functions.reduceRight((result, obj) =>
result.map((item) => obj.func(item, ...(obj.args || [])))
, array);
}
And in the main program, print the return value:
console.log(s.add(plus, 1).add(timesTwo).evaluate([1, 2, 3]));
The add method has also some strange logic, like:
When the first if condition is false, then the else block kicks in with args.length == 0. It is then strange to see conditions on args.length... it really is 0!
If the first condition in func.length <= args.length + 1 || func.length === args.length is false, then surely the second will always be false also. It should not need to be there.
argsArrayNumeric is never used.
All in all, it seems the code could be reduced to this snippet:
class Lazy {
constructor() {
this.functions = [];
}
add(func, ...args) {
if (func.length > args.length + 1) {
throw ValueError(`Missing parameters for ${func.name} function`);
}
this.functions.push({ func, args });
return this;
}
evaluate(array) {
return this.functions.reduceRight((result, obj) =>
result.map((item) => obj.func(item, ...(obj.args || [])))
, array);
}
}
const timesTwo = (a) => a * 2;
const plus = (a, b) => a + b;
const s = new Lazy();
console.log(s.add(plus, 1).add(timesTwo).evaluate([1, 2, 3])); // [3, 5, 7]
I think you're working too hard at this. I believe this does almost the same thing (except it doesn't report arity errors; that's easy enough to include but doesn't add anything to the discussion):
class Lazy {
constructor () {
this .fns = []
}
add (fn, ...args) {
this .fns .push ({fn, args});
return this
}
evaluate (xs) {
return xs .map (
x => this .fns .reduce ((a, {fn, args}) => fn (...args, a), x)
)
}
}
const timesTwo = (a) => a * 2
const plus = (a, b) => a + b
const s = new Lazy () .add (timesTwo) .add (plus, 1)
console .log (s .evaluate ([1, 2, 3]))
But I don't actually see much of a reason for the class here. A plain function will do much the same:
const lazy = (fns = [], laze = {
add: (fn, ...args) => lazy (fns .concat ({fn, args})),
evaluate: (xs) => xs .map (
x => fns .reduce ((a, {fn, args}) => fn (...args, a), x)
)
}) => laze
const timesTwo = (a) => a * 2
const plus = (a, b) => a + b
const s = lazy () .add (timesTwo) .add (plus, 1)
console .log (s .evaluate ([1, 2, 3]))
This is slightly different in that s is not mutated on each add, but a new object is returned. While we could change that and mutate and return the original object easily enough, the functional programming purist in me would actually consider moving more in that direction. In fact, all we're maintaining here is a list of {fn, args} objects. It might make the most sense to take that on directly, like this:
const add = (lazy, fn, ...args) => lazy .concat ({fn, args})
const evaluate = (lazy, xs) => xs .map (
x => lazy .reduce ((a, {fn, args}) => fn (...args, a), x)
)
const timesTwo = (a) => a * 2
const plus = (a, b) => a + b
const q = []
const r = add (q, timesTwo)
const s = add (r, plus, 1)
// or just
// const s = add (add ([], timesTwo), plus, 1)
console .log (evaluate (s, [1, 2, 3]))
In this version, we don't need a Lazy constructor or a lazy factory function, as our data structure is a plain array. While this is the format I prefer, any of these should do something similar to what you're trying.
Update
Based on comments, I include one more step on my journey, between the first and second snippets above:
const lazy = () => {
const fns = []
const laze = {
add: (fn, ...args) => fns .push ({fn, args}) && laze,
evaluate: (xs) => xs .map (
x => fns .reduce((a, {fn, args}) => fn (...args, a), x)
)
}
return laze
}
const timesTwo = (a) => a * 2
const plus = (a, b) => a + b
const s = lazy () .add (timesTwo) .add (plus, 1)
console .log (s .evaluate ([1, 2, 3]))
This version may be more familiar than the second snippet. It stores fns in a closure, hiding implementation details in a way we often don't with JS classes. But that list is still mutable through the add method of the object we return. Further ones proceed down the road to immutability.

Implementing lazy evaluation for `reduceRight()` function in JavaScript

A problem in the codewars.com:
https://www.codewars.com/kata/foldr/train/javascript
Define a foldr function for array which implement the same function like built-in function reduceRight(). The problem is very abstract because I knew few about functional programming.
I find the most important is how to implement lazy-evaluation in the JavaScript. But I don't know how to deal with it.
For example, we have two functions, indexOf and logging, indexOf(x) is a function which will be called as arguments in the foldr method, logging is a wrapper function which tell us how many times indexOf(x) could be called.
const indexOf = y => function (cur, acc) {
if (cur === y) {
return 0
} else {
return acc + 1 || -1
}
};
const logging = fn => function logging(...a) {
i++;
return fn(...a);
};
If we implement it without laziness and use recursion:
Object.defineProperty(Array.prototype, "foldr", {
value: function foldr(fn, z) {
return function _foldr(a) {
if (a.length === 0) {
return z
}
return fn(a[0], _foldr(a.slice(1)))
}(this);
}
});
let i = 0
let x = [1, 2, 3].foldr(logging(indexOf(1)), -1)
console.log(`x: ${x}`) // x: 0
console.log(`i: ${i}`) // i: 3
The variable i shows that the function has been called 3 times, the whole array has been iterated. However, if we observe the indexOf funciton we'll find that we don't need to iterate the whole array if we use lazy evaluation.
In the first level of recursion
indexOf(1)(a[0], _foldr(a.slice(1))) equals indexOf(1)(1, _foldr([2,3])), because cur === y, it should return 0 immediately and doesn't need to evaluate the second argument _foldr([2,3]). So in the test case of the codewars.com, the i should be 1.
How could I deal with it?
You are close ...:
fn(a[0], () => _foldr(a.slice(1)))
If you pass a function instead of the accumulator value, the function can decide to evaluate the accumulator or not:
const indexOf = y => function (cur, acc) {
if (cur === y) {
return 0; // acc() was not called, ends here
} else {
return acc() + 1 || -1; // acc() gets called, traversal goes on
}
};
I find the solution. Use Object.prototype.valueOf()
The valueOf() method returns the primitive value of the specified object.
Because we'd like to call the function when we do some algorithms such as return acc + 1 || -1.
We could use:
Object.defineProperty(Array.prototype, 'foldr', {
value(fn, z) {
let _foldr = (a) => {
if (!a.length) return z;
let r = fn(a[0], { valueOf: () => _foldr(a.slice(1)) });
return (r.valueOf) ? r.valueOf() : r;
};
return _foldr(this);
},
});

How does reduce work in this scenario?

I was looking into pipe functions and I came across this reduce function which takes the _pipe function as the parameter. The _pipe function has two params a,b and then returns another function.
How does reduce work here?
add3 = x => x + 3;
add5 = x => x + 5;
const _pipe = (a, b) => (arg) => b(a(arg))
const pipe = (...ops) => ops.reduce(_pipe)
const add = pipe(add3, add5)
add(10)
output
18
look at pipe function definition:
const pipe = (...ops) => ops.reduce(_pipe)
It receives array of functions called ops (this is called rest params).
Then we call reduce for ops array. Reducer function has 2 params: accumulator and current value.
Here is our _pipe written with human readable variables:
const _pipe = (accumulator, currentValue) => (arg) => currentValue(accumulator(arg));
So the result of _pipe will be curried functions from ops array.
If it's [add3, add5] then result will be (arg) => add3(add5(arg))
If it's [add3, add5, add2] then result is: (arg) => add2(accumulator(arg)) where accumulator is (arg) => add3(add5(arg)).
You simply compose all functions from array using reduce. Then pass initial value which is 10.
It's like: add3(add5(10)) = 18
the reduce function is equivalent to
add3 = x => x + 3;
add5 = x => x + 5;
const _pipe = (a, b) => (arg) => b(a(arg))
const pipe = (...ops) => {
// create a base function
let sum = x => x;
// for every operation
for (let op of ops) {
// call _pipe with sum and it
// equivalent to sum = x => sum(op(x))
sum = _pipe(sum, op)
}
// return the resulting function
return x => sum(x)
}
const add = pipe(add3, add5)
console.log(add(10))

piping functions in JavaScript

How can I have a JavaScript function let's say piper() which takes several functions as its arguments and it returns a new function that will pass its argument to the first function, then pass the result to the second, then
pass the result of the second to the third, and so on, finally returning the output of the last function.
Something like piper(foo, fee, faa)(10, 20, 30) would be equivalent to calling faa(fee(foo(10,20,30))).
ps:
It was a part of an interview, that I did few days ago.
For an arbritrary number of functions you could use this ES6 function:
function piper(...fs) {
return (...args) => fs.reduce((args,f) => [f.apply(this,args)],args)[0];
}
// Example call:
var result = piper(Math.min, Math.abs, Math.sqrt)(16, -9, 0)
// Output result:
console.log(result);
The same in ES5 syntax:
function piper(/* functions */) {
var fs = [].slice.apply(arguments);
return function (/* arguments */) {
return fs.reduce(function (args,f) {
return [f.apply(this,args)];
}.bind(this), [].slice.apply(arguments))[0];
}.bind(this);
}
// Example call:
var result = piper(Math.min, Math.abs, Math.sqrt)(16, -9, 0)
// Output result:
console.log(result);
Enjoy. Pure ES5 solution. Preserves this.
function piper(){
var i = arguments.length,
piped = arguments[ --i ];
while( --i >= 0 ){
piped = pipeTwo( arguments[ i ], piped );
}
return piped;
}
function pipeTwo( a, b ){
return function(){
return a.call( this, b.apply( this, arguments ) );
}
}
Or, if you want the fancy solution.
function piperES6( ...args ){
return args.reverse().reduce( pipeTwo );
}
Loops can be reversed depending on the desired direction.
Very similar to #trincot's answer (preserves context), but composes in the correct order and is marginally faster since it does not create intermediary arrays:
const piper = (...steps) => function(...arguments) {
let value = steps[0].apply(this, arguments);
for (let i = 1; i < steps.length; ++i) {
value = steps[i].call(this, value);
}
return value;
};
// Usage:
let p = piper(
x => x + 1,
x => x * 2,
x => x - 1
);
console.log(p(2)); // 5
Here is an alternative answer involving method chaining. I shall use ES6, though of course this can be transpiled to ES5. On benefit of this solution is that is has a very succinct TypeScript counterpart with perfect typeability.
class Pipe {
constructor(value) {
this.value = value;
}
then(f) {
return new Pipe(f(this.value));
}
}
const pipe = value => new Pipe(value);
// Example
const double = x => 2 * x;
pipe(42).then(double).then(console.log); // 84
const result = pipe(42).then(double).then(double).value;
console.log(result); // 168
A simple solution based on JS higher-order functions usage:
function pipe(...rest) {
return x => rest.reduce((y, f) => f(y), x);
}
Usage:
pipe((a) => a + 1, (a) => a * 2)(3) // 8
pipe((a) => a + 1, (a) => a * 2)(2) // 2
function f(f1, f2, f3){
return (args => f3(f2(f1(args))));
}
I think what you are trying to do is chaining.
var funct={
total:0,
add:function(a) {
console.log(funct.total,funct.total+a);
funct.total+=a;
return funct;
}
};
funct.add(5).add(6).add(9);

Categories