Currying function with unknown arguments in JavaScript - javascript

In a recent interview, I was asked to write a function that adds numbers and accepts parameters like this:
add(1)(2)(3) // result is 6
add(1,2)(3,4)(5) // result is 15
The number of parameters is not fixed, and the arguments can be either passed in sets or individually.
How can I implement this add function?

Given your examples, the number of parameters is fixed in some ways.
As #ASDFGerte pointed out, your examples seem to return the result after three invocations. In this case a simple implementation without introducing terms like variadic and currying could be
function add(...args1){
return function(...args2){
return function(...args3){
return args1.concat(args2).concat(args3).reduce((a,b)=>a+b)}}}
console.log(add(1)(2)(3))
console.log(add(1,2)(3,4)(5))
Every invocation accepts a variable number of parameters.
However it would be nice to generalize the construction of this nested functions structure and you can accomplish that with currying.
But if you want to allow an arbitrary number of invocations, when you should stop returning a new function and return the result? There is no way to know, and this is a simple, unaccurate and partial explanation to give you the idea of why they said you cannot accomplish what they asked you.
So the ultimate question is: is it possible that you misunderstood the question? Or maybe it was just a trick to test you
Edit
Another option would be to actually invoke the function when no arguments are passed in, change the call to add(1)(2)(3)()
Here an example recursive implementation
function sum (...args) {
let s = args.reduce((a,b)=>a+b)
return function (...x) {
return x.length == 0 ? s : sum(s, ...x)
};
}
console.log(sum(1,2)(2,3,4)(2)())
At every invocation computes the sum of current parameters and then return a new function that:
if is invoked without parameters just return the current sum
if other numbers are passed in, invokes recursively sum passing the actual sum and the new numbers

I'm a bit late to the party, but something like this would work (a bit hacky though in my opinion):
const add = (a, ...restA) => {
const fn = (b, ...restB) => {
return add([a, ...restA].reduce((x, y) => x + y) + [b, ...restB].reduce((x, y) => x + y))
};
fn.valueOf = () => {
return [a, ...restA].reduce((x, y) => x + y)
};
return fn;
}
This function returns a function with a value of the sum. The tests below are outputing the coerced values instead of the actual functions.
console.log(+add(1,2)(3,4)(5)); // 15
console.log(+add(1)) // 1
console.log(+add(1)(2)) // 3
console.log(+add(1)(2)(3)) // 6
console.log(+add(1)(2)(3)(4)) // 10
Since it's a currying function, it will always return another function so you can do something like this:
const addTwo = add(2);
console.log(+addTwo(5)); // 7

using reduce and spread it can be done as below
function calc(...args1){
return function (...args2){
return function (...args3){
let merge = [...args1, ...args2, ...args3]
return merge.reduce((x ,y)=> x + y) ;
}
}
}
let sum = calc(10)(1)(4);
console.log("sum",sum);

They probably wanted to know how comfortable you were with "javascript internals", such as how and when methods like Function#toString and Function#valueOf, Function#[Symbol.toPrimitive] are called under the hood.
const add = (...numbers) => {
const cadd = (...args) => add(...args, ...numbers);
cadd[Symbol.toPrimitive] = () => numbers.reduce((a, b) => a + b);
return cadd;
}
console.log(
`add(1,2)(3,4)(5) =>`, add(1,2)(3,4)(5),
); // result is 15
console.log(
`add(1,2) =>`, add(1,2),
); // result is 3
console.log(
`add(1,2)(5)(1,2)(5)(1,2)(5)(1,2)(5) =>`, add(1,2)(5)(1,2)(5)(1,2)(5)(1,2)(5),
); // result is 32

Related

Closure with a Lazy Adder Function

I'm stuck on a problem that uses a closure function to add the arguments of subsequent functions into a sum function:
Write a function named: lazyAdder(firstNum). The lazyAdder function
will accept a number and return a function. When the function returned
by lazyAdder is invoked it will again accept a number, (secondNum),
and then return a function. When the last mentioned function is
invoked with a number, (thirdNum), it will FINALLY return a number.
See below for examples!
Example 1:
let firstAdd = lazyAdder(1);
let secondAdd = firstAdd(2);
let sum = secondAdd(3);
console.log(sum); // prints 6
Example 2:
let func1 = lazyAdder(10);
let func2 = func1(20);
let total = func2(3);
console.log(total); // prints 33
I tried:
const lazyAdder = f => g => h => x => f(g(h))(h(x));
Thinking it takes in two function inputs (firstNum + secondNum = sum1), then adds a third (thirdNum + sum1 = sum2).
This did invoke the function twice; however, it did not return the sum - it returned an anonymous function.
If I get it correctly, what you are tasked to do is to perform a sum in a sequence of evaluations (i.e. pass arguments at different times). In a non-lazy approach, you would simply make a function sum which takes 3 parameters x, y and z and sum this: sum(1, 2, 3) = 7. Now to do this the "lazy" way, you have to perform an operation on this function called currying. I suggest reading up on this, as this is essentially what is asked.
Currying such a function can be done quite easily in JavaScript. As you showed, you can just chain the arguments in a function declaration:
const func = arg1 => arg2 => arg3 => ... // Some logic performed here
Now you can call this function 3 times until it returns something other than a closure; a value.
How do you make sure that when you func(1)(2)(3) it returns the sum, which is 6?
Since I suspect this is a homework assignment, I do not want to give you the plain answer. Therefore, it is up to you to define what logic should be put inside the function to sum these values. What is important is that the definition I gave, is already a definition of lazy evaluation.

Is there a possible way to check for second parentheses in a function?

I'm working on a Javascript challenge. The challenge is the code below in which you add the numbers provided together:
function addTogether() {
//I left this blank because I'm focused on checking for the second parentheses
}
However, if you tried to pass this addTogether(5)(7) to the function addTogether(), it would be difficult to get the second parentheses.
However, you can get both parentheses if you write this code:
function addTogether() {
//get first parenteses
let first = arguments;
//get second parentheses
let second = function() {
return arguments;
};
}
But my question is how do you check if there's a second parentheses? Because I'm passing other data such as addTogether(2,3). In other words, I might be passing some with one parentheses and another with two parentheses to the function addTogether()
There is no way to check, unless you're parsing the source code, but your function can optionally accept second argument and if it's provided return the sum, otherwise return a function
const addTogether = (a, opt) => opt ? a + opt : b => a + b
console.log("addTogether(1,3) => ", addTogether(1,3))
console.log("addTogether(4)(6) => ", addTogether(4)(6))
Naive implementation using function that coerces to number.
Using reduce to calculate sums. Overriding ##toPrimitive to create function that coerces to value of add. Recursive call to generate recursively chainable callable number coercable functions.
Check ECMAScript specs if you want to customize behavior further. You will need to understand the conversion path.
function sum(...args) {
const first = args.reduce((sum,x)=>sum+x,0)
const second = function(...args) {return sum(first, ...args)}
second[Symbol.toPrimitive] = function(){return first}
return second
}
console.log(
1+sum(1)(2)+sum(1)+sum(3),
sum(1,1,2) (1,3)(0)(0)+sum(0,-1,1,0),
sum(1)(1)(2)(1)(3)(0)(0)(-1,1)(0)+sum()
)

JavaScript - Modify arguments before executing function

Given I have a function called sum module imported from a 3rd party module Calculator. Here's how I use it:
Calculator.sum(1, 2) // returns 3
I don't know the implementation of Calculator.sum. What if I want to modify the arguments passed to Calculator.sum before executing sum, so that instead of taking the original numbers (1, 2, 3, etc), sum will take their squared values (1, 4, 9, etc) ? For example:
Calculator.sum(1, 2) // returns 5
Calculator.sum(2, 3) // returns 13
Calculator.sum(3, 4) // returns 25
Note: This is just an example of my actual problem, I don't actually need a Calculator.sum function to calculate sum of squares 😀
Couldn't you just store it under another name and overwrite it ?
Calculator.sum_stored = Calculator.sum;
Calculator.sum = function(a,b){
return Calculator.sum_stored(Math.sqrt(a),Math.sqrt(b));
};
Then you can just call Calculator.sum as you wanted to.
You could simply decorate the original function with you extra functionality, then call the original function with whatever values you wish.
If you are going to do something like this, you should really define a different function eg, calulator.squareAdd.
// this is your library object
const Calculator = {
sum: (...args) => args.reduce((x, y) => x + y, 0)
}
console.log(
'before decoration',
Calculator.sum(1, 2)
)
// save a reference to the original function
const origSum = Calculator.sum
// decorate the sum function with your own function
Calculator.sum = function(...args) {
return origSum.apply(Calculator, args.map(x => Math.pow(x, 2)))
}
// call the decorated function
console.log(
'after decoration',
Calculator.sum(1, 2), // returns 5
Calculator.sum(2, 3), // returns 13
Calculator.sum(3, 4) // returns 25
)
<script src="https://codepen.io/synthet1c/pen/KyQQmL.js"></script>
You can modify the arguments in side the method like this ->
Calculator.sum(a,b) {
return a*a + b*b;
}
And if you want your method to be flexible then you can pass a third argument that will identify what operation needs to be performed on the arguments.
Calculator.sum(a,b,'square'){
//use switch case here to return the correct result.
}

ES6 double arrow parameters (i.e. const update = x => y => { } ) [duplicate]

This question already has answers here:
javascript es6 double arrow functions
(2 answers)
Closed 5 years ago.
What does double arrow parameters mean in the following code?
const update = x => y => {
// Do something with x and y
}
How is it different compared to the following?
const update = (x, y) => {
// Do something with x and y
}
Thanks!
Let's rewrite them "old style", the first one is:
const update = function (x) {
return function(y) {
// Do something with x and y
};
};
While the second one is:
const update = function (x, y) {
// Do something with x and y
};
So as you can see they are quite different, the first returns an "intermediate" function, while the second is a single function with two parameters.
There's nothing special about "double arrow parameters", this is just one arrow function returning another, and can be extended for as many arguments as you'd like. It's a technique called "currying".
From Wikipedia:
In mathematics and computer science, currying is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument.
The benefit of this is that it makes it easier to partially apply and compose functions, which is useful for some styles of functional programming.
Example
Let's say you have a function add which takes two numbers and adds them together, which you might traditionally write like this:
const add = (a, b) => a + b;
Now let's say you have an array of numbers and want to add 2 to all of them. Using map and the function above, you can do it like this:
[1, 2, 3].map(x => add(2, x));
However, if the function had been in curried form, you wouldn't need to wrap the call to add in another arrow function just to adapt the function to what map expects. Instead you could just do this:
const add = a => b => a + b;
[1, 2, 3].map(add(2));
This is of course a trivial and rather contrived example, but it shows the essence of it. Making it easier to partially apply functions also makes it more practical to write small and flexible functions that can be composed together, which then enables a much more "functional" style of programming.
That are called arrow functions, it the new format for functions presented by ES6, in the first example
const update = x => y => {
// Do something with x and y
}
can be traduced to
var update = function (x){
return function (y){
// Do something with x and y..
}
}
in ES5, and is a function that returns a function
is totally different than
const update = function (x, y) {
// Do something with x and y
};
The syntax PARAM => EXPR represents a function that takes a parameter PARAM and whose body is { return EXPR; }. It is itself an expression, so it can be used as the EXPR of other functions:
x => y => { ... }
parses as
x => (y => { ... })
which is the same as
x => { return y => { ... }; }

create compose function in functional programming approach

I am trying to understand how compose works by recreating compose. As part of that I've created a simple calculator to take a value and based on that value return interest.
https://medium.com/javascript-scene/reduce-composing-software-fe22f0c39a1d#.rxqm3dqje
Essentially ultimate goal is to create a function that can do below.
https://github.com/ngrx/example-app/blob/master/src/app/reducers/index.ts#L150
Nice to have: been able to pass multiple deposit values, and and may be calculate compound interest over time.
It would be good have some comments so I understand what is going on from Functional programming approach.
(()=>{
// Generic compose function to handle anything
const compose = (...fns) => (x) => {
return fns.reduceRight((acc,fn)=>{
return fn(acc);
}, x)
};
const getInterest = (value) => {
if (value < 1000) {
return 1 / 100
}
if (value < 10000) {
return 2 / 100
}
return 3 / 100;
};
const getDeposit = (value) => {
return value;
};
const calculator = compose(getDeposit, getInterest)
console.log(calculator(1000)) // Should return value of 1000 * interest rate. I currently get 0.03
})();
The issue is that you never multiply the two values: value and interest.
You should therefore pass another function into the composition, which will multiply the two previous results.
This means that this function will need to get 2 arguments, while the other two only take one. In general a function could need any number of arguments. So the composer should be able to pass enough arguments to each function. Furthermore, functions may also return more than one value -- in the form of an array. These values should be made available as arguments for the next function in the chain, while keeping any previous returned values available as well.
Another thing is that although you have implemented compose to execute the functions from right to left, the sequence of function you pass seem to suggest you expect them to execute from left to right, first getDeposit, and then getInterest, even though in your case it works both ways. Still, I would suggest to switch their positions.
So here is how you can make all that work:
(()=>{
// Generic compose function to handle anything
const compose = (...fns) => (...args) => {
return fns.reduceRight((acc,fn)=>{
// Call the function with all values we have gathered so far
let ret = fn.apply(null, acc);
// If function returns a non-array, turn it into an array with one value
if (!Array.isArray(ret)) ret = [ret];
// Queue the returned value(s) back into the accumulator, so they can
// serve as arguments for the next function call
acc.unshift(...ret);
return acc;
}, args)[0]; // only return the last inserted value
};
const getInterest = (value) => {
return value < 1000 ? 0.01
: value < 10000 ? 0.02
: 0.03;
};
const multiply = (a, b) => a * b;
const getDeposit = (value) => value;
// Be aware the the rightmost function is executed first:
const calculator = compose(multiply, getInterest, getDeposit);
console.log(calculator(1000)) // Returns 20, which is 0.02 * 1000
})();
Alternative: pass along an object
The above implementation is not a pure compose implementation, since it passes not only the previous function result on to the next, but all previous functions results. This is not disturbing, and opens doors for more complex functions, but if you wanted to stick more to the original compose idea, you have a problem to solve:
As you want to have a function in the chain that only returns the rate, the next function in the chain will then only get the rate -- nothing else. With just that one piece of information it is of course not possible to calculate the result, which also needs the value as input.
You could "solve" this, by letting getInterest return an object, that not only has the rate in it, but also the value that was passed to it. You could also implement this with an array.
Here it is with an object implementation:
(()=>{
// Straightforward implementation:
const compose = (...fns) => (...args) => {
return fns.reduceRight((acc,fn)=>{
return fn(acc);
}, args);
};
// Return an object with two properties: value & interest
const getInterest = (value) => ({
value,
interest: value < 1000 ? 0.01
: value < 10000 ? 0.02
: 0.03
});
// Expect an object as argument, with two properties:
const getInterestAmount = ({value, interest}) => value * interest;
const getDeposit = (value) => value;
// Be aware the the rightmost function is executed first:
const calculator = compose(getInterestAmount, getInterest, getDeposit);
console.log(calculator(1000)) // Returns 20, which is 0.02 * 1000
})();
With this approach you can pass along objects that have many more properties, and so anything becomes possible.
I actually liked your simple compose function (it just only works for unary functions), and I think you can also make it work for now by making these changes:
rename getInterest to ...Rate, since it returns a multiplier for a value.
add a new getInterest function that takes a "rate getter" and a "value" in curried form: getRate => x => getRate(x) * x
swap the order of your calculator arguments in compose
I think compose usually works from right to left (f => g => x
=> f(g(x))), and pipe works from left to right (f => g => x => g(f(x)))
(()=>{
// Generic compose function to handle anything
const compose = (...fns) => (x) => {
return fns.reduceRight((acc,fn)=>{
return fn(acc);
}, x)
};
const defaultRate = (value) => {
if (value < 1000) {
return 1 / 100
}
if (value < 10000) {
return 2 / 100
}
return 3 / 100;
};
const getInterest = getRate => x => getRate(x) * x;
const getDeposit = x => 1000;
const calculator = compose(getInterest(defaultRate), getDeposit);
console.log(calculator());
})();

Categories

Resources