Puzzle: a JS function that returns itself until there are no arguments

I'm trying to solve a riddle, and I'm in my mind trying to figure it out.

I have to create a function that works as follows:

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

I know this can be done because other people have successfully completed the puzzle. I tried several different ways to do this. This is my last attempt:

 function add(n) { //Return new add(n) on first call if (!(this instanceof add)) { return new add(n); } //Define calc function var obj = this; obj.calc = function(n) { if (typeof n != "undefined") { obj.sum += n; return obj.calc; } return obj.sum; } //Constructor initializes sum and returns calc(n) obj.sum = 0; return obj.calc(n); } 

The idea is that the first call initializes a new add(n) and starts calc(n) . If calc receives a parameter, it adds n to sum and returns itself. When it finally does not receive the parameter, it returns the value sum .

That makes sense in theory, but I can't get it to work. Any ideas?

- edit -

My code is just the route I chose. I am not opposed to a different approach if anyone can think about it.

+5
source share
5 answers

To answer "how it works." Given:

 function add(n) { function calc(x) { return add(n + x); } calc.valueOf = function() { return n; } return calc; } var sum = add(1)(2)(3); // 6 

When add is called for the first time, it stores the value passed in variable n. Then it returns a calc function that has a closure on n and a special valueOf method (explained below).

Then this function is called with a value of 2, so it calls add with the sum n + x , which is 1 + 2 , which is 3.

So, a new version of calc returns, this time with a closure on n with a value of 3.

This new calc is called with a value of 3, so it calls add with n + x , which this time is 3 + 3 , which is 6

Again adds returns a new calc with n set to 6. Last time calc is no longer called. The return value is assigned to the variable sum. All calc functions have a special valueOf method that replaces the standard one provided by Object.prototype . Normally valueOf just returns a function object, but in this case it will return n.

Now the sum can be used in expressions, and if its valueOf method is called, it will return 6 (i.e. the value of n held in the closure).

It looks pretty cool, and the sum will act like a primitive number, but actually it is a function:

 typeof sum == 'function'; 

Therefore, be careful with strictly checking the type of things:

 sum * 2 // 12 sum == 6 // true sum === 6 // false -- oops!! 
+11
source

Here are some streamlined versions of @RobG's excellent answer:

 function add(n) { function calc(x) { return n+=x, calc; } calc.valueOf = function() { return n; }; return calc; } 

The slight difference is that here calc simply updates n and then returns itself, rather than returning itself through another call to add , which pushes another frame onto the stack.

Explicit expression of self-replication

calc is thus a pure self-reproducing function, returning itself. We can encapsulate the concept of "self-replication" function

 function self_replicate(fn) { return function x() { fn.apply(this, arguments); return x; }; } 

Then add can be written, perhaps in a more self-documenting way, since

 function add(n) { function update(x) { n += x; } var calc = self_replicate(update); calc.valueOf = function() { return n; }; return calc; } 

Parallel to the # reduce array

Please note that between this approach there is some parallelism of multiple function calls and Array#reduce . Both reduce the list of things to one value. In the case of Array#reduce list is an array; in our case, the list is the parameters for repeated calls. Array#reduce defines a standard signature for reducer functions, namely

 function(prev, cur) 

where prev is the "accumulator" (so far), cur is the new value that is being supplied, and the return value becomes the new accumulator value. It seems useful to rewrite our implementation to use a function with such a signature:

 function add(n) { function reducer(prev, cur) { return prev + cur; } function update(x) { n = reducer(n, x); } var calc = self_replicate(update); calc.valueOf = function() { return n; }; return calc; } 

Now we can create a more general way to create reducers based on replication based on the reducer function:

 function make_repeatedly_callable_function(reducer) { return function(n) { function update(x) { n = reducer(n, x); } var calc = self_replicate(update); calc.valueOf = function() { return n; }; return calc; }; } 

Now we can create add as

 var add = make_repeatedly_callable_function(function(prev, cur) { return prev + cur; }); add(1)(2); 

In fact, Array#reduce calls the reducer function with the third and fourth arguments, namely the index into the array and the array itself. The latter does not matter here, but perhaps we would like something like the third argument to find out what an "iteration" is, which we can easily handle, just by tracking the use of the variable i :

 function reduce_by_calling_repeatedly(reducer) { var i = 0; return function(n) { function update(x) { n = reducer( n, x, i++); } var calc = self_replicate(update); calc.valueOf = function() { return n; }; return calc; }; } 

Alternative approach: value tracking

There are certain advantages to tracking intermediate parameters called by a function (using an array) and then performing the reduction at the end, rather than as you move. For example, we could make Array#reduceRight type of things:

 function reduce_right_by_calling_repeatedly(reducer, initialValue) { var array_proto = Array.prototype, push = array_proto.push, reduceRight = array_proto.reduceRight; return function(n) { var stack=[], calc = self_replicate(push.bind(stack)); calc.valueOf = reduceRight.bind(stack, reducer, initialValue); return calc(n); }; } 

Non-Primitive Objects

Try using this approach to create objects ("expand"):

 function extend_reducer(prev, cur) { for (i in cur) { prev[i] = cur[i]; } return prev; } var extend = reduce_by_calling_repeatedly(extend_reducer); extend({a: 1})({b: 2}) 

Unfortunately, this will not work because Object#toValue is only called when a primitive object is required by JS. Therefore, in this case, we must explicitly call toValue :

 extend({a: 1})({b: 2}).toValue() 
+4
source

Thanks for the help on valueOf() . This is what works:

 function add(n) { var calc = function(x) { return add(n + x); } calc.valueOf = function() { return n; } return calc; } 

- edit -

Could you explain how this works? Thanks!

I don’t know if I know the correct vocabulary to describe exactly how this works, but I will try:

Example: add(1)(1)

When add(1) is called, a reference to calc returned.

  • calc understands that n is that, in the minds of the interpreter, calc is a child of the add function. When calc searches for n and does not find it locally, it searches for scope chain and finds n .

  • So, when calc(1) is called, it returns add(n + x) . Remember, calc knows that n is, and x is just the current argument (1) . Adding is actually done inside calc , so it returns add(2) at that point, which in turn returns another calc reference.

Step 2 can be repeated every time we have another argument (i.e. (x) ).

  • If there are no arguments left, we leave only a definition of calc . The last calc never called because calling a function requires () . At this point, the interpreter usually returns a calc function object. But since I tried calc.valueOf , it runs this function.

  • When calc.valueOf is executed, it finds the last instance of n in the scope chain, which is the cumulative value of all previous n .

Hope this made some sense. I just saw @RobG's explanation, which admittedly is much better than mine. Read this if you are confused.

+1
source

Here's an option using bind :

 var add = function _add(a, b) { var boundAdd = _add.bind(null, a + b); boundAdd.valueOf = function() { return a + b; } return boundAdd; }.bind(null, 0); 

We use the bind function, which allows us to set default arguments for the function to which we are bound. From the docs:

bind () also takes default leading arguments to provide the target function when calling the associated function.

So _add acts as a kind of main function that takes two parameters a and b . It returns a new boundAdd function, which is created by binding the original _add function a to a + b ; it also has an overridden valueOf function that returns a + b (the valueOf function was well explained in @RobG's answer).

To get the initial add function, the bind _add a parameter is 0 .

Then, when add(1) is called, a = 0 (from our initial bind call) and b = 1 (the argument passed). It returns a new function, where a = 1 (bound to a + b ).

If we then call this function using (2) , which sets b = 2 and returns a new function, where a = 3 .

If we then call this function using (3) , which sets b = 3 and returns a new function, where a = 6 .

And so on until valueOf is called, after which it will return a + b . Which after add(1)(2)(3) would be 3 + 3 .

+1
source

This is a very simple approach, and it meets the criteria that the OP is looking for. Namely, the function is passed an integer, tracks this integer and returns itself as a function. If the parameter is not passed, the function returns the sum of the integers passed to it.

 let intArray = []; function add(int){ if(!int){ return intArray.reduce((prev, curr) => prev + curr) } intArray.push(int) return add } 

If you call it like this:

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

outputs 2.

0
source

Source: https://habr.com/ru/post/1201459/


All Articles