How can I make var a = add(2)(3); //5 work?
Asked Answered
C

33

54

I want to make this syntax possible:

var a = add(2)(3); //5

based on what I read at http://dmitry.baranovskiy.com/post/31797647

I've got no clue how to make it possible.

Coign answered 16/2, 2010 at 12:44 Comment(1)
See also: Syntax of ClosureDupuy
H
108

You need add to be a function that takes an argument and returns a function that takes an argument that adds the argument to add and itself.

var add = function(x) {
    return function(y) { return x + y; };
}
Heriot answered 16/2, 2010 at 12:49 Comment(5)
The ES2015 arrow syntax facilitates the job: const add = x => y => x + y;Deformed
@Heriot I'm new in JS. And I have a doubt. Why it(var add = function() should not be function add(){ }? function add() also give the same result.Possessed
@Possessed the syntax I've shown defines an anonymous function and assigns it to the variable named add. The second defines a named function with the name add. They both work.Heriot
@Heriot I think my below solution is more exciting with unlimited adding chainEijkman
Could you please tell me, do we have any specific name for this kind of syntax, I have got the same kind of question from my interviewer last nightEscarp
A
40
function add(x) {
    return function(y) {
        return x + y;
    };
}

Ah, the beauty of JavaScript

This syntax is pretty neat as well

function add(x) {
    return function(y) {
        if (typeof y !== 'undefined') {
            x = x + y;
            return arguments.callee;
        } else {
            return x;
        }
    };
}
add(1)(2)(3)(); //6
add(1)(1)(1)(1)(1)(1)(); //6
Afterimage answered 16/2, 2010 at 12:52 Comment(8)
if (y) should be if (typeof y === "undefined"), since zero is a valid argument.Iolaiolande
@dionadar well, not exactly (0) will return the value of x wich is not a function so you can't add anything else after you've used (0).Afterimage
Can we do something to eliminate the last empty brackets, like making add(1)(2)(3) = 6 and add(1)(2)(3)(4) = 10? I was asked to write such a function and got stuken then.Overcharge
See my answer for a solution without the final ()Wavellite
how do you make it work with one argument as well as currying, e.g. add(1) === 1, and add(1)(2) === 3Husch
Useful note: arguments.callee removed from ES5 strict modeGerge
My below answer works well with out a last empty variable ()Eijkman
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… apparently arguments.callee is no good anymore... :-SLeatherback
E
19

It's about JS curring and a little strict with valueOf:

function add(n){
  var addNext = function(x) {
    return add(n + x);
  };

  addNext.valueOf = function() {
    return n;
  };

  return addNext;
}

console.log(add(1)(2)(3)==6);//true
console.log(add(1)(2)(3)(4)==10);//true

It works like a charm with an unlimited adding chain!!

Eijkman answered 13/7, 2018 at 3:20 Comment(6)
const add = (a) => { let f = (b) => add(a + b) f.valueOf = () => a return f }Husch
What in the bloody heck is going on when assigning values?! Your same example behaves differentlly with this escenarios: a) console.log(' should equal 6 => ', add(1)(2)(3)); b) console.log('should NOT matter', add(1)(2)(3) === 6); Can you please explain what's going under the hood (besides rotenJS which is obviouse ;) )Pondweed
Because func valueOf of add will return a stringEijkman
It's only working for number comparison. How to get value instead of function body after last add call, anyone?Wanhsien
I know that writing "thanks" in comments is a big no-no. But just this once, thanks. Really.Ambiguity
It even works for add(1). It would be great, if you gave an expanded explanation.Community
P
15
function add(x){
  return function(y){
    return x+y
  }
}

First-class functions and closures do the job.

Peppercorn answered 16/2, 2010 at 12:50 Comment(0)
W
14
function add(n) {
  sum = n;
  const proxy = new Proxy(function a () {}, {
    get (obj, key) {
      return () => sum;
    },
    apply (receiver, ...args) {
      sum += args[1][0];
      return proxy;
    },
  });
  return proxy
}

Works for everything and doesn't need the final () at the end of the function like some other solutions.

console.log(add(1)(2)(3)(10));    // 16
console.log(add(10)(10));         // 20
Wavellite answered 14/10, 2016 at 21:41 Comment(6)
Wow can you explain this, I have no idea what's going on.Husch
So I mostly referenced 2ality.com/2014/12/es6-proxies.html when I was learning about Proxies but the short version of this is that in javascript you can create traps for pretty much every operation. Luckily the operations for applying a function are different than the one where the value is determined. So I trapped both the apply and the getter of a function to create this. You probably already do this in your es6 classes with getters and setters (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…) this is just a bit more explicitWavellite
@GaleelBhasha not sure why jsFiddle isn't working but it works in repl.it (repl.it/repls/DirectPolitePasswords) and in my local node repl.Wavellite
Proxy is oke, but I think my below answer is easier and readable!Eijkman
@hien I didn't even consider that, that is a really cool solution.Wavellite
It's a cool sulotion!Sou
P
13

try this will help you in two ways add(2)(3) and add(2,3)

1.)

 function add(a){ return function (b){return a+b;} }

    add(2)(3) // 5

2.)

function add(a,b){
        var ddd = function (b){return a+b;};
        if(typeof b =='undefined'){
            return ddd;
        }else{
            return ddd(b);
        }
    }

add(2)(3) // 5
add(2,3) // 5
Petiolate answered 12/12, 2014 at 13:25 Comment(0)
P
11

ES6 syntax makes this nice and simple:

const add = (a, b) => a + b;

console.log(add(2, 5)); 
// output: 7

const add2 = a => b => a + b;

console.log(add2(2)(5));
// output: 7
Photochronograph answered 24/10, 2016 at 19:54 Comment(3)
how do you make it work with one argument as well as currying, e.g. add(1) === 1, and add(1)(2) === 3Husch
@AymonFournier I'm not 100% sure, but I think it is not possible for add(1) to return both a Function and a Number value at the same time. At the time of calling add(1), you cannot be sure whether there is going to be another call with 2 as argument, or whether this is the final call.Jazmin
@AymonFournier Oh, I stand corrected, a trick is to use valueOf(). See someone else's answer for more details: https://mcmap.net/q/334530/-how-can-i-make-var-a-add-2-3-5-workJazmin
S
7

Arrow functions undoubtedly make it pretty simple to get the required result:

const Sum = a => b => b ? Sum( a + b ) : a;

console.log(Sum(3)(4)(2)(5)()); //14

console.log(Sum(3)(4)(1)()); //8
Sacramentarian answered 28/2, 2019 at 2:7 Comment(1)
when you go this far its amazing. and also its easy to forget that 3+4+2+5 is not 19 :)Ojeda
K
4

This is a generalized solution which will solve add(2,3)(), add(2)(3)() or any combination like add(2,1,3)(1)(1)(2,3)(4)(4,1,1)(). Please note that few security checks are not done and it can be optimized further.

function add() {
	var total = 0;

	function sum(){
		if( arguments.length ){
			var arr = Array.prototype.slice.call(arguments).sort();
			total = total + arrayAdder(arr);
			return sum;
		}
		else{
			return total;
		}
	}

	if(arguments.length) {
		var arr1 = Array.prototype.slice.call(arguments).sort();
		var mytotal = arrayAdder(arr1);
		return sum(mytotal);
	}else{
		return sum();
	}

	function arrayAdder(arr){
		var x = 0;
		for (var i = 0; i < arr.length; i++) {
			x = x + arr[i];
		};
		return x;
	}
}
add(2,3)(1)(1)(1,2,3)();
Kirkham answered 10/1, 2016 at 9:4 Comment(0)
H
4

This will handle both

add(2,3) // 5

or

add(2)(3) // 5

This is an ES6 curry example...

const add = (a, b) => (b || b === 0) ? a + b : (b) => a + b;
Happening answered 11/5, 2018 at 21:15 Comment(0)
V
4

This is concept of currying in JS.
Solution for your question is:

function add(a) {
  return function(b) {
    return a + b;
  };
}

This can be also achieved using arrow function:

let add = a => b => a + b;

solution for add(1)(2)(5)(4)........(n)(); Using Recursion

function add(a) {
  return function(b){
    return b ? add(a + b) : a;
  }
}

Using ES6 Arrow function Syntax:

let add = a => b => b ? add(a + b) : a;
Valdes answered 22/7, 2020 at 6:19 Comment(0)
S
3

in addition to what's already said, here's a solution with generic currying (based on http://github.com/sstephenson/prototype/blob/master/src/lang/function.js#L180)

Function.prototype.curry = function() {
    if (!arguments.length) return this;
    var __method = this, args = [].slice.call(arguments, 0);
    return function() {
      return __method.apply(this, [].concat(
        [].slice.call(args, 0),
        [].slice.call(arguments, 0)));
   }
}


add = function(x) {
    return (function (x, y) { return x + y }).curry(x)
}

console.log(add(2)(3))
Scrofula answered 16/2, 2010 at 13:55 Comment(1)
nice solution, but some would object to adding stuff in the prototypeChapland
H
2

Concept of CLOSURES can be used in this case.
The function "add" returns another function. The function being returned can access the variable in the parent scope (in this case variable a).

function add(a){

    return function(b){
        console.log(a + b);
    }

}


add(2)(3);

Here is a link to understand closures http://www.w3schools.com/js/js_function_closures.asp

Haily answered 28/5, 2016 at 18:13 Comment(0)
S
2

With ES6 spread ... operator and .reduce function. With that variant you will get chaining syntax but last call () is required here because function is always returned:

function add(...args) {
    if (!args.length) return 0;
    const result = args.reduce((accumulator, value) => accumulator + value, 0);
    const sum = (...innerArgs) => {
        if (innerArgs.length === 0) return result;
        return add(...args, ...innerArgs);    
    };
    return sum;
}




// it's just for fiddle output
document.getElementById('output').innerHTML = `
<br><br>add() === 0: ${add() === 0 ? 'true' : 'false, res=' + add()}
<br><br>add(1)(2)() === 3: ${add(1)(2)() === 3 ? 'true' : 'false, res=' + add(1)(2)()}
<br><br>add(1,2)() === 3: ${add(1,2)() === 3 ? 'true' : 'false, res=' + add(1,2)()}
<br><br>add(1)(1,1)() === 3: ${add(1)(1,1)() === 3 ? 'true' : 'false, res=' + add(1)(1,1)()}
<br><br>add(2,3)(1)(1)(1,2,3)() === 13: ${add(2,3)(1)(1)(1,2,3)() === 13 ? 'true' : 'false, res=' + add(2,3)(1)(1)(1,2,3)()}
`;
<div id='output'></div>
Stenson answered 5/5, 2017 at 15:3 Comment(0)
B
2
const add = a => b => b ? add(a+b) : a;

console.log(add(1)(2)(3)());

Or (`${a} ${b}`) for strings.

Biceps answered 29/1, 2018 at 0:14 Comment(0)
R
2

can try this also:

let sum = a => b => b ? sum(a + b) :a
console.log(sum(10)(20)(1)(32)())   //63
Roderickroderigo answered 30/6, 2021 at 20:26 Comment(0)
M
2
const sum  = function (...a) {
    const getSum = d => {
        return d.reduce((i,j)=> i+j, 0);
    };

    a = getSum(a);
    return function (...b) {
        if (b.length) {
            return sum(a + getSum(b)); 
        }
        return a;
    }
};
console.log(sum(1)(2)(3)(4,5)(6)(8)())
Marcellamarcelle answered 15/8, 2021 at 17:40 Comment(0)
I
1
function add(a, b){
 return a && b ? a+b : function(c){return a+c;}
}

console.log(add(2, 3));
console.log(add(2)(3));
Inverse answered 27/8, 2016 at 21:40 Comment(0)
I
1

This question has motivated so many answers already that my "two pennies worth" will surely not spoil things.

I was amazed by the multitude of approaches and variations that I tried to put "my favourite" features, i. e. the ones that I would like to find in such a currying function together, using some ES6 notation:

const add=(...n)=>{
 const vsum=(a,c)=>a+c;
 n=n.reduce(vsum,0);
 const fn=(...x)=>add(n+x.reduce(vsum,0));
 fn.toString=()=>n; 
 return fn;
}

let w=add(2,1); // = 3
console.log(w()) // 3
console.log(w); // 3
console.log(w(6)(2,3)(4)); // 18
console.log(w(5,3)); // 11
console.log(add(2)-1); // 1
console.log(add()); // 0
console.log(add(5,7,9)(w)); // 24
.as-console-wrapper {max-height:100% !important; top:0%}

Basically, nothing in this recursively programmed function is new. But it does work with all possible combinations of arguments mentioned in any of the answers above and won't need an "empty arguments list" at the end.

You can use as many arguments in as many currying levels you want and the result will be another function that can be reused for the same purpose. I used a little "trick" to also get a numeric value "at the same time": I redefined the .toString() function of the inner function fn! This method will be called by Javascript whenever the function is used without an arguments list and "some value is expected". Technically it is a "hack" as it will not return a string but a number, but it will work in a way that is in most cases the "desired" way. Give it a spin!

Imprecate answered 23/7, 2020 at 5:58 Comment(0)
P
1

Simple Recursion Solution for following use cases

add(); // 0

add(1)(2)(); //3

add(1)(2)(3)(); //6
function add(v1, sum = 0) {
  if (!v1) return sum;
  sum += v1
  return (v2) => add(v2, sum);
}
Petro answered 13/5, 2021 at 5:42 Comment(0)
M
1

// executor function
const sum = (a,b,c) => a+b+c;

// curried function
function curry(fn){
  return function curried(...args) {
    if(args.length >= fn.length){
      return fn.apply(this,args);
    } else {
      return function (...arg) {
        return curried(...arg, ...args)
      }
    }
  }
}

const curriedSum = curry(sum);
console.log(curriedSum(1,2,3));
console.log(curriedSum(1)(2)(3));
console.log(curriedSum(1)(2,3));
Marcellamarcelle answered 27/12, 2022 at 14:25 Comment(1)
Welcome to SO! Please don't post code-only answers but add a little textual explanation about how and why your approach works and what makes it different from the other answers given. You can find out more at our "How to write a good answer" page.Heim
B
0

function add() { var sum = 0;

    function add() {
        for (var i=0; i<arguments.length; i++) {
            sum += Number(arguments[i]);
        }
        return add;
    }
    add.valueOf = function valueOf(){
        return parseInt(sum);
    };
    return add.apply(null,arguments);
}

// ...

console.log(add() + 0);               // 0
console.log(add(1) + 0);/*                 // 1
console.log(add(1,2) + 0);               // 3
Brocklin answered 17/9, 2017 at 18:7 Comment(0)
B
0
function A(a){
  return function B(b){
      return a+b;
  }
}

I found a nice explanation for this type of method. It is known as Syntax of Closures

please refer this link Syntax of Closures

Bedroll answered 11/10, 2017 at 5:59 Comment(0)
B
0

Simply we can write a function like this

    function sum(x){
      return function(y){
        return function(z){
          return x+y+z;
        }
      }
    }

    sum(2)(3)(4)//Output->9
Brockwell answered 18/12, 2018 at 11:55 Comment(0)
B
0

Don't be complicated.

var add = (a)=>(b)=> b ? add(a+b) : a;
console.log(add(2)(3)()); // Output:5

it will work in the latest javascript (ES6), this is a recursion function.

Bugs answered 13/7, 2019 at 6:34 Comment(0)
T
0

Here we use concept of closure where all the functions called inside main function iter refer and udpate x as they have closure over it. no matter how long the loop goes , till last function , have access to x.

function iter(x){    
return function innfunc(y){
//if y is not undefined
if(y){
//closure over ancestor's x
x = y+x;
return innfunc;
}
else{
//closure over ancestor's x
return x;
    }
  }
}

iter(2)(3)(4)() //9 iter(1)(3)(4)(5)() //13

Thermotaxis answered 21/7, 2019 at 16:51 Comment(0)
R
0

let multi = (a)=>{
	return (b)=>{
		return (c)=>{
			return a*b*c
		}
	}
}
multi (2)(3)(4) //24

let multi = (a)=> (b)=> (c)=> a*b*c;
multi (2)(3)(4) //24
Rrhagia answered 16/9, 2019 at 5:28 Comment(0)
M
0

we can do this work using closure.

    function add(param1){
      return function add1(param2){
      return param2 = param1 + param2;
    }
  }
  console.log(add(2)(3));//5
Maltha answered 15/11, 2019 at 5:47 Comment(0)
B
0

I came up with nice solution with closure, inner function have access to parent function's parameter access and store in its lexical scope, when ever we execute it, will get answer

    const Sum = function (a) {
        return function (b) {
            return b ? Sum(a + b) : a;
        }
    };

    Sum(1)(2)(3)(4)(5)(6)(7)() // result is 28
    Sum(3)(4)(5)() // result is 12
    Sum(12)(10)(20) // result is 42

enter image description here

Burnell answered 6/12, 2019 at 9:26 Comment(1)
Hi and welcome to stackoverflow, and thank you for your answer. Rather than just posting a block of code, can you give a short explanation to what the issue is you solved and how you solved it? This will help people who find this question in the future to better understand the issue and how to deal with it.Trader
T
0

You should go in for currying to call the function in the above format.

Ideally, a function which adds two numbers will be like,

let sum = function(a, b) {
  return a + b;
}

The same function can be transformed as,

let sum = function(a) {
  return function(b) {
    return a+b;  
  }
}

console.log(sum(2)(3));

Let us understand how this works.

When you invoke sum(2), it returns

function(b) {
    return 2 + b;
}

when the returned function is further invoked with 3, b takes the value 3. The result 5 is returned.

More Detailed Explanation:

let sum = function(a) {
  return function(b) {
    return a + b;
  }
}

let func1 = sum(2);
console.log(func1);

let func2 = func1(3)
console.log(func2);

//the same result can be obtained in a single line

let func3 = sum(2)(3);
console.log(func3);

//try comparing the three functions and you will get more clarity.
Telson answered 5/2, 2021 at 12:32 Comment(0)
R
0

This is a short solution:

const add = a => b => {
  if(!b) return a;
  return add(a + b);
}

add(1)(2)(3)() // 6
add(1)(2)(3)(4)(5)() // 15
Rhapsodize answered 8/12, 2022 at 12:13 Comment(0)
M
-1

function add () {
    var args = Array.prototype.slice.call(arguments);
 
    var fn = function () {
        var arg_fn = Array.prototype.slice.call(arguments);
        return add.apply(null, args.concat(arg_fn));
    }
 
    fn.valueOf = function () {
        return args.reduce(function(a, b) {
            return a + b;
        })
    }
 
    return fn;
}

console.log(add(1));
console.log(add(1)(2));
console.log(add(1)(2)(5));

from http://www.cnblogs.com/coco1s/p/6509141.html

Milter answered 28/4, 2017 at 3:17 Comment(0)
L
-1
    let add = (a, b) => b === undefined ? add.bind(null, a) : a + b;
    console.log(add(10, 5)); //15
    console.log(add(10)(5)); //15

/* In the arrow function which returns a ternary expression, we explicitly check if the 2nd argument(b) is passed in or not b==="undefined" in both cases of add(a,b) and add(a)(b).

  1. if "undefined" in the case of add(a)(b) it uses "add.bind(null,a)", the "bind" method is associated with all functions(functions are objects) which creates a new function that is returned by the arrow function and passes in:
    • "null" for the first argument "the context its binding to which allows it to default to the window object"
    • "a" the second argument to be returned with the new function.
    • so when the new function is called at this point add(a)>>>(b) "b" is no longer undefined so the ternary switches to a+b.
  2. If not b==="undefined" in the case of add(a, b) the ternary switches to a+b */
Lira answered 7/12, 2019 at 3:25 Comment(2)
While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value.Excruciating
thanks for the advice, does the addition of the edited comments sufficeLira

© 2022 - 2024 — McMap. All rights reserved.