-2

I recently failed a JavaScript Interview test and couldn't get feedback from the employer on some of the answers, one question in particular. The test was set up with Mocha tests that you had to write the code for it to pass. The Test was :

describe('Step 5', function() {

  it('add(2,8)(5).value() => 15', function() {
    add(2,8)(5).value()
      .should.be.exactly(15).and.be.a.Number;
  });

  it('add(3, 3, 5)(4)(3, 2).value() => 20', function() {
    add(3, 3, 5)(4)(3, 2).value()
      .should.be.exactly(20).and.be.a.Number;
  });
});

Can someone help with the answer and also explain how/why and possibly when you might use this?

georg
  • 211,518
  • 52
  • 313
  • 390
fauxdev
  • 35
  • 1

3 Answers3

4
describe('Step 5', function() {

  var curry = function (fn) {
    return function () {
      var args = [],
          accumulate = function accumulate() {
            args = args.concat(Array.prototype.slice.call(arguments));
            return accumulate;
          };
      accumulate.value = function () {
        return fn.apply(null, args);
      };
      accumulate.apply(null, arguments);
      return accumulate;
    };
  },
      add = curry(function () {
        return Array.prototype.reduce.call(arguments, function (total, number) {
          return total + number;
        }, 0);
      });

  it('add(2,8)(5).value() => 15', function() {
    add(2,8)(5).value()
      .should.be.exactly(15).and.be.a.Number;
  });

  it('add(3, 3, 5)(4)(3, 2).value() => 20', function() {
    add(3, 3, 5)(4)(3, 2).value()
      .should.be.exactly(20).and.be.a.Number;
  });
});

Pass a function fn to curry to create a function that, when called, creates a function that accumulates the arguments passed to it over time, and returns itself. You can apply the accumulated arguments to fn by calling the value method attached to the function returned from the function returned from curry.

In this case you can create an add function which adds up an arbitrary number of arguments, and have that receive the accumulated arguments.

Personally I have never had the opportunity to use this technique. But apparently it's a good interview question, so as for the "how, why and when:" Probably to get hired.

Jackson
  • 9,188
  • 6
  • 52
  • 77
3

In this assignment you were expected to understand partial application of functions. Assume you've got a function with two arguments:

> function plus(a, b) { return a + b }
> plus(1,5)
6

Now, what happens if you call it with less arguments?

> plus(1)
NaN

This isn't particularly helpful - Javascript simply uses the default undefined for the second argument and the function breaks. A smarter way to handle that would be to "freeze" the first argument and when the second one comes, perform the action on both. Then, plus(1)(5) would return 6. To do that, we rewrite plus so that it returns another function that already contains the first argument and accepts the second one:

> function plus(a) { return function(b) { return a + b } }
> plus(1)(5)
6

This process of "freezing" function arguments is called "partial application". Functions that do that automatically when called with less arguments are "curried" functions. In javascript they are not used widely, but most functional languages support them out of the box.

The actual solution to your assignment is slightly more complicated and I leave it as an exercise (see if this answer helps).

Community
  • 1
  • 1
georg
  • 211,518
  • 52
  • 313
  • 390
1

I think the "tricky" part of the question is related to the chaining of () in method call. add(2, 8)(5) is not the same thing as add(2, 8, 5). For the first call (thus, in your exercice), your add method should return a function, not the result of the addition.

See more here: Function calling in Javascript with double brackets

Community
  • 1
  • 1
Romain Linsolas
  • 79,475
  • 49
  • 202
  • 273