2

Recently i faced one problem in hackerrank which has to calculate multiplication operation and has to return the answer. For example

function multiply(a,b) {
     return a*b;
}

Now here is the problem the function might call in different ways such as

multiply(4,5);
multiply(4)(5);
multiply(4)(5)(6);

I know we have to closure apporach for the second one which is multiply(4)(5). I had written code for that

function multiply(a,b) {
  return function(b) {
    return a*b;
  }
}

Now what if its been multiply function has been called with 3 arguments multiply(4)(5)(6). How can i identify how the function has been called and how can i write a common solution for all the inputs.

Any help is appreciated. Thanks

Kannan T
  • 1,639
  • 5
  • 18
  • 29
  • 1
    Read some tutorials on *"currying"* functions – charlietfl Nov 14 '17 at 13:23
  • 1
    Look at this tutorial, http://benalman.com/news/2012/09/partial-application-in-javascript/ . It's explain how partial function and currying works in javascript. That will solve your problem. – Nathan Meunier Nov 14 '17 at 13:25

3 Answers3

3

To have an unlimited callchain you need some js trick:

function multiply(...args){
  //make the chain endless through using some recursive like stuff:
  const func = (...args2) => multiply(...args,...args2);
  //the chains endpoint:
  func.valueOf = function(){
     return args.reduce((a,b) => a*b);
  };
  return func;
}

The problem of such variable currying is that its infinite, so theres ( usually ) no way to end it.

multiply(1) // func :/

However in javascript its possible to assign methods to functions so we can easily somewhen call the method instead of the function to end the chain:

multiply(1)(2)(3).valueOf()

So you can simply do:

 console.log(
  +multiply(1,2,3)(4)(5),
  +multiply(1,2)
);

The + is equal to valueOf and is therefore neccessary to end the chain, however this call to valueOf is inferred by many operations in javascript ( all math operations like - * /).

Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • @artgb no way. Just some ways to *infer* it, e.g. you could change *valueOf* to *toString*, and then `document.body.innerHTML = multiply(1)(2)(3)` ( see jsbin) or `alert( multiply(1,2,3))` – Jonas Wilms Nov 14 '17 at 14:04
  • Jonas thanks allot for this answer it works finely but am having hard time understanding how it works can you break it down and explain? Thanks – Kannan T Nov 14 '17 at 17:16
  • @kannan you're welcome ;) could we do it the other way round, i mean could you ask specifically the parts you're not understanding? – Jonas Wilms Nov 14 '17 at 17:57
  • First thing i dont understand is what is " ..." passed in argument (...args) – Kannan T Nov 15 '17 at 16:25
  • @kannan thats a rest parameter, so basically everything you pass in in an array – Jonas Wilms Nov 15 '17 at 17:01
  • https://jsfiddle.net/xLaykxjk/1/ check out this i edited the code for my understanding and i don't understand the function – Kannan T Nov 16 '17 at 18:07
  • @kannan yeah well the `.reduce((a,b) => a*b)` reduces the *args* array by multiplying all of the elements with each other – Jonas Wilms Nov 16 '17 at 18:44
  • @ jonas no not that reduce function bro am confused with .valueOf and .toString – Kannan T Nov 16 '17 at 18:49
  • @kannan well i just set a function to a property of func which is a function itself – Jonas Wilms Nov 16 '17 at 19:33
  • Why do we want to do that can we just perform reduce function without it what is the necessary for that – Kannan T Nov 17 '17 at 05:19
  • 1
    @kannan without we can't exit the chain. The function needs to return a function to make that chain infinite, so the only way to also expose the result is to make it a part of that function – Jonas Wilms Nov 17 '17 at 06:04
1

The Problem with this approach is the ambiguity of the returned value. It has to be a Number AND a function, both at the same time.

due to the valueOf() method you can simulate that behaviour, but I'd rarely reccomend to use that in production.

const wrap = (accumulator, value) => {
  let fn = (...args) => args.length? wrap(accumulator, args.reduce(accumulator, value)): fn;
  fn.valueOf = () => value;
  return fn;
}

let mul = wrap((a,b) => a*b, 1);

console.log(+mul(4,5));
console.log(+mul(4,5)(6));
console.log(mul(4,5) * 6);
console.log(+mul(4)(5,6)(7)(8,9)()(10));

//or maybe a different operation?
let add = wrap((a,b) => a+b, 0);

console.log(+add(1,2,3,4,5));
.as-console-wrapper{top:0;max-height:100%!important;}

Downside of this approach, it's made so flexible (and ambigious), it's pretty much useless since it's way too hard to grasp what result you'll get when using this somewhere inline. What if some functions you'll feed this into do a typecheck? Then you're in trouble.

Thomas
  • 11,958
  • 1
  • 14
  • 23
0

You're close, what you are trying to do is called currying, a technique that takes advantage of closures.

In this case, your function should only take one argument at a time:

function multiply(a) {
    return function(b) {
        return a * b;
    }
}

Now you could say

function multiplyBy5 = multiply(5);
console.log(multiplyBy5(4)); //would log 20

If you're only expecting at max 3 arguments you could do:

function multiply(a) {
    return function(b) {
        return function(c) {
            c = c || 1;
            return a * b * c;
        }
    }
}

Which makes c an optional argument. You can call that function by

multiply(4)(5)()

//or

multiply(4)(5)(6)
Robbie Milejczak
  • 5,664
  • 3
  • 32
  • 65
  • but this way `multiply(3)(4)` will return `f (c) { ....` instead of 12, will not it? – skyboyer Nov 14 '17 at 13:30
  • yes that's up to OP to figure out and I'm sure he can, I don't feel right completely solving someone's hackerrank problem but this should be a good start – Robbie Milejczak Nov 14 '17 at 13:32
  • Yes, for sure, I see your point. It just seems to be really interesting question. Function can have custom valueOf(). So this way it could act as a function() and as a value in the same time. – skyboyer Nov 14 '17 at 18:51
  • 1
    yeah, currying is an awesome concept it can be leveraged for a lot of efficiency in a codebase by letting you reuse a single multi purpose function for specific purposes. It's great for readability and also it's just a cool and novel programming concept. Check out this vid series for some similar concepts https://www.youtube.com/watch?v=BMUiFMZr7vk&list=PL0zVEGEvSaeEd9hlmCXrk5yUyqUag-n84 I think functional programming in javascript is a lot of fun – Robbie Milejczak Nov 14 '17 at 19:55