Function Currying: Javascript Questions
Tags: javascript, interview, webdev
Published: 2022-09-11 13:54:12

#A Little Introduction

Currying happens when a function does not receive all of its parameters at once. It instead takes the first parameter and returns a different function. The returned function should be invoked with the second parameter, which should return another function.This continues until all the arguments have been presented. The function at the end of the chain will then be the one that returns the desired value.

```js
// This is a normal function
sum(1,2,3)

// while this is a curried function
sum(1)(2)(3)
```

> It is important to note that currying only alters the construct of a function and not it's functionality.


## Question-1: sum(1)(2)

This is fairly straightforward. The syntax might be a bit weird to those who see it for the first time. Basically, we keep returning a function and pass it one argument. This continues after we have finished passing all the arguments. At the last stage, we have access to all the previously passed arguments due to the power of closures. It is at this stage, that we execute our logic.

```js
function sum(a){
 return function(b){
   return a + b;
 }
}

// dry-run
// add(1)(2)
// step - 1: add(1) executes and returns a function

// (function(b){
//   return 1 + b;
// })(2)

// step - 2: returned function executes with 2 passed as parameter.

// (function(2){
//   return 1 + 2 //> it gets value of 1 from closure!
// })

// outputs 3

console.log(sum(1)(2)) //logs 6

```

## Question-2: sum(1)(2)(3)(4)...(n)()

This question is a direct extension of the first one. Catch is, number of arguments can be infinite! This problem is commonly known as **infinite currying** and is a popular interview question.

> Always solve for a smaller subproblem.

```js
// with 2 arguments
function sum2(a){
 return function(b){
   return a + b;
 }
}

// with 3 arguments
function sum3(a){
 return function(b){
   return function(c){
     return a + b + c;
   }
 }
}

// notice the pattern here ? At every level,
// If there is another argument left, we return a new function
// else we execute the logic. Recursive thinking is required for // these pattern of problems.

//with n-arguments
function sum(a) {
  return function(b){
    if(b){
      return sum(a+b);
    }
    return a;
  }
}

// dry-run
// example -> sumN(1)(2)(3)(4)

// step-1 
//   sumN(1) executes

// step-2 
//   (function(b){
//     if(b){
//       return sumN(1+b);
//     }
//     return a;
//   })(2)(3)(4)

// step-3
//    (function(2){
//     if(2){
//       return sumN(1+2); // again call to sum
//     }
//     //> won't execute
//     return a;
//   })(3)(4)
  

// // Notice the recursive pattern ?
// step-4 
//    (function sumN(3) {
//     return function(b){
//       if(b){
//         return sumN(3+b);
//       }
//       return a;
//     }
// })(3)(4)

// step-5
//   (function sumN(3) {
//   return function(3){
//     if(b){
//       return sumN(3+3);
//     }
//     return a;
//   }
// })(4)

// step-6
//  (function sumN(6) {
//   return function(b){
//     if(b){
//       return sumN(6+b);
//     }
//     return a;
//   }
// })(4)

// step-7
//   (function(4){
//     if(4){
//       return sumN(6+4);
//     }
//     return a;
//   })

// step-8
//   sumN(10)

// step-9
//   (function(undefined){
//     if(undefined){
//       //> won't execute
//       return sum(a+b);
//     }
//     return 10;
//   })()

// step-10
//   logs 10
```

**I'd highly recommend writing the code in any IDE and do a dry run yourself**

## Question-3 sum(1,2,...,n)(3,4,...,n)...(n)()

We are stepping up the game here. In this pattern, number of arguments in a single call can be infinite as well! We will use knowledge gained from the last problem to solve this.

_hint_: _this problem can directly be reduced to the last problem_

```js
// we just reduce the arguments into a single argument for
// a single call! Now it's just like the previous problem!
function sum(...args) {
  let a = args.reduce((a, b) => a + b, 0)
  return function(...args){
    let b = args.reduce((a, b) => a + b, 0)
    if(b){
      return sum(a+b)
    }
    return a
  }
}
```

## Question-4 implement function currify

Currify will be a function that takes in another function as argument and returns a currified version of the same function! Note that it does not modify the functionality of the passed function by any means. It only transforms the function.

Now, this one is a little tricky.

The general idea to solve the problem is like this:

- Currify will take a function as argument.
- Currify will return another function.
- The use-case of that function will be to somehow store all the arguments that are being passed, until there are no more arguments to pass.
- Once all the arguments are exhausted, we can simply call the passed function with all the accumulated arguments and our job will be done.


below is the above idea expressed in code.

```js
function currify(fn) {
  return function saveCurryArgs() {
    const args = Array.prototype.slice.call(arguments); // a
    if (args.length >= fn.length) // b
      return fn.apply(null,args); //c
    else 
      return saveCurryArgs.bind(null, ...args); //d
  }
}

const multiply = function(a,b,c){
  return a + b + c 
}

const curryMultiply  = currify(multiply);

// logs 6
console.log(curryMultiply(1)(2)(3));
```

Let's understand exactly what it's doing and how it's doing it.
I've commented main logic points in the code with alphabets.

a) We construct our list of arguments from the [_array-like object_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice#array-like_objects) [**arguments**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments).

b) _args.length_ represents arguments received so far. _fn.length_ denotes the total number of arguments that are to be processed.

c) This logic executes after we have exhausted all our arguments. We simply use the _apply_ method on _fn_.

d) Else, we save the current arguments with all the previous arguments by calling _bind_ over the _saveCurryArgs_ function.

With this, our logic for currify is complete!


## Conclusion

If you've managed to come this far, congratulations! Currying is an extremely important topic from an interview point of view as well as real world use-cases. I'd again recommend coding out the examples over [codepen ](https://codepen.io/)or your local IDE. Hope you enjoyed the article! Thanks for the read!