1a. Create Currying Function which works for all possible calls of 5 arguments.
const CurrySum = (...args) => {
const ARGS_LENGTH = 5;
if (args.length === ARGS_LENGTH) {
return args.reduce((prev, curr) => prev + curr, 0);
}
const recursiveSum = (...args2) => {
args = args.concat(args2);
if (args.length === ARGS_LENGTH) {
return args.reduce((prev, curr) => prev + curr, 0);
}
return recursiveSum;
};
return recursiveSum;
};
console.log(CurrySum(1)(2)(3)(4)(5));
console.log(CurrySum(1, 2)(3)(4)(5));
console.log(CurrySum(1, 2, 3)(4)(5));
console.log(CurrySum(1, 2, 3, 4)(5));
console.log(CurrySum(1, 2, 3, 4, 5));
console.log(CurrySum(1, 2)(3, 4, 5));
console.log(CurrySum(1)(2, 3, 4, 5));
console.log(CurrySum(1, 2, 3)(4, 5));
console.log(CurrySum(1, 2, 3, 4)(5));
// Output:
15
15
15
15
15
15
15
15
15
1b. Create Currying Function which works for infinite arguments.
const Sum = (...args1) => {
const storage = [...args1];
if (storage.length === 0) {
return 0;
}
const curriedSum = (...args2) => {
if (args2.length === 0) {
return storage.reduce((prev, curr) => prev + curr, 0);
}
storage.push(...args2);
return curriedSum;
};
return curriedSum;
};
const res1 = Sum(1, 2, 3, 4)();
const res2 = Sum(1)(2)(3)(4)();
const res3 = Sum(1, 2)(3, 4)();
const res4 = Sum(1, 2, 3)(4)();
const res5 = Sum(1)(2, 3, 4)();
const res6 = Sum();
console.log(res1, res2, res3, res4, res5, res6);
// 10 10 10 10 10 0
2. Create Currying Function which return sum of previous values.
const CurrySum = () => {
let prevSum = 0;
return (newValue = 0) => {
prevSum += newValue;
return prevSum;
};
};
const sum = CurrySum();
console.log(sum());
console.log(sum(1));
console.log(sum(4));
console.log(sum(3));
console.log(sum(3));
console.log(sum());
// Output:
0
1
5
8
11
11
3. What is Currying?
Currying is a function that takes one argument at a time and returns a new function expecting the next argument.
It is a conversion of functions from callable as f(a,b,c) into callable as f(a)(b)(c).
4. Why should we use Currying?
- It makes a function pure which makes it expose to less errors and side effects.
- It helps in avoiding the same variable again and again.
- It is a checking method that checks if you have all the things before you proceed.
- It divides one function into multiple functions so that one handles one set of responsibility.
5. Make this Sum work - sum(2)(6)(1)
function sum(num1, num2, num3) {
return num1 + num2 + num3;
}
function currySum(num1) {
return (num2) => {
return (num3) => {
return num1 + num2 + num3;
};
};
}
console.log(sum(2, 6, 1)); // 9
console.log(currySum(2)(6)(1)); // 9
6. Currying Evaluate Function
function evaluate(operation) {
return (num1) => {
return (num2) => {
if (operation === "add") return num1 + num2;
if (operation === "sub") return num1 - num2;
if (operation === "mul") return num1 * num2;
if (operation === "div") return num1 / num2;
};
};
}
console.log(evaluate("add")(4)(2)); // 6
console.log(evaluate("sub")(4)(2)); // 2
console.log(evaluate("mul")(4)(2)); // 8
console.log(evaluate("div")(4)(2)); // 2
7. Infinite Currying - sum(1)(2)(3)........(n)
function add(a) {
return (b) => {
if (b) return add(a + b);
return a;
};
}
console.log(add(1)(2)(3)(4)(100)()); // 110
8. Currying v/s Partial Application
Number of return functions in Currying depends on the number of arguments we pass in.
But in Partial Application, that is not the case.
Partial Application transforms a function into another function with small arity (Latin: number of arguments).
// Currying
function currySum(a) {
return (b) => {
return (c) => {
return a + b + c;
};
};
}
console.log(currySum(1)(2)(3)); // 6
// Partial Application
function partialSum(a) {
return (b, c) => {
return a + b + c;
};
}
console.log(partialSum(1)(2, 3)); // 6
9. Currying in DOM Manipulation
h1 heading with id heading.
Run the below code. The h1 will become Maddy
function updateElementText(id) {
const ele = document.getElementById(id);
return (content) => {
ele.textContent = content;
};
}
const heading = updateElementText("heading");
heading("Arjunan");
heading("John");
heading("Maddy");
10. Create a Curry function to convert Normal Functions to Currying Functions.
function Curry(fn) {
return function curriedFn(...args1) {
if (args1.length >= fn.length) {
return fn(...args1);
}
return (...args2) => {
return curriedFn(...args1, ...args2);
};
};
}
const sum = (a, b, c) => {
console.log(a + b + c);
};
sum(1)(2)(3);
// sum(...) is not a function
const currySum = Curry(sum);
currySum(1, 2, 3); // 6
currySum(1)(2); //
currySum(1)(2)(3); // 6
11. Create Curry Fn to convert Normal Functions with infinite args to Curried Functions.
function Curry(fn) {
return function curriedFn(...args1) {
if (args1.length === 0) {
return fn.call(this);
}
return (...args2) => {
if (args2.length === 0) {
return fn.apply(this, args1);
}
return curriedFn(...args1, ...args2);
};
};
}
const sum = (...args) => {
console.log(args.reduce((prev, curr) => prev + curr, 0));
};
const currySum = Curry(sum);
currySum(); // 0
currySum(1)(2)(); // 3
currySum(1)(2)(3)(); // 6
currySum(1, 1)(2, 2)(3)(); // 9
currySum(1, 1)(2, 2)(3); // returns the function
12. Write a function that satisfies currying + .value() function call.
console.log(add(1)(2).value() == 3); // true
console.log(add(1, 2)(3).value() == 6); // true
console.log(add(1)(2)(3).value() == 6); // true
console.log(add(1)(2) + 3); // 6
When JavaScript wants to turn an object into a primitive value (Primitive values are data that are stored directly in a variable.), it uses the function valueOf()
method. JavaScript automatically calls the function valueOf() method when it comes across an object where a primitive value is anticipated, so you don’t even need to do it yourself.
The valueOf() method of Object instances converts the this value to an object. This method is meant to be overridden by derived objects for custom type conversion logic.
function MyNumberType(n) {
this.number = n;
}
const object1 = new MyNumberType(4);
console.log(object1 + 3); // [object Object]3
MyNumberType.prototype.valueOf = function () {
return this.number;
};
const object2 = new MyNumberType(4);
console.log(object2 + 3); // 7
Thus we can form closure and track the arguments in an Array and return a new function every time that will accept new arguments. We will also override the valueOf()
method and return the sum of all the arguments for each primitive action, also add a new method value()
that will reference the valueOf()
thus when invoked will return the sum of arguments.
function add(...args1) {
let sum = [...args1];
function curriedSum(...args2) {
sum = [...sum, ...args2];
return curriedSum;
}
curriedSum.valueOf = () => {
return sum.reduce((prev, curr) => prev + curr, 0);
};
curriedSum.value = curriedSum.valueOf;
return curriedSum;
}
console.log(add(1)(2).value() == 3); // true
console.log(add(1, 2)(3).value() == 6); // true
console.log(add(1)(2)(3).value() == 6); // true
console.log(add(1)(2) + 3); // 6