From 5965ae79a888ff1d7b757888f2b2510ea9570b7d Mon Sep 17 00:00:00 2001 From: Lakshya Thakur Date: Sat, 9 Jan 2021 17:00:00 +0530 Subject: [PATCH 1/2] Update currying function to use bind instead of wrapper pass I think this change will help us to dodge concatenating new arguments with lexical ones and make the currying function much simpler. --- .../03-currying-partials/article.md | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/1-js/99-js-misc/03-currying-partials/article.md b/1-js/99-js-misc/03-currying-partials/article.md index bb308847..2f91197f 100644 --- a/1-js/99-js-misc/03-currying-partials/article.md +++ b/1-js/99-js-misc/03-currying-partials/article.md @@ -121,11 +121,7 @@ function curry(func) { return function curried(...args) { if (args.length >= func.length) { return func.apply(this, args); - } else { - return function(...args2) { - return curried.apply(this, args.concat(args2)); - } - } + } else return curried.bind(this, ...args); }; } @@ -154,26 +150,22 @@ The result of `curry(func)` call is the wrapper `curried` that looks like this: function curried(...args) { if (args.length >= func.length) { // (1) return func.apply(this, args); - } else { - return function pass(...args2) { // (2) - return curried.apply(this, args.concat(args2)); - } - } + } else return curried.bind(this, ...args); }; ``` When we run it, there are two `if` execution branches: 1. Call now: if passed `args` count is the same as the original function has in its definition (`func.length`) or longer, then just pass the call to it. -2. Get a partial: otherwise, `func` is not called yet. Instead, another wrapper `pass` is returned, that will re-apply `curried` providing previous arguments together with the new ones. Then on a new call, again, we'll get either a new partial (if not enough arguments) or, finally, the result. +2. Get a partial: otherwise, `func` is not called yet. Instead, a new bounded function using curried is returned, that takes the `...args` i.e. the current arguments as pre-specified. Then on a new call, again, we'll get either a new partial (if not enough arguments) or, finally, the result. For instance, let's see what happens in the case of `sum(a, b, c)`. Three arguments, so `sum.length = 3`. For the call `curried(1)(2)(3)`: -1. The first call `curried(1)` remembers `1` in its Lexical Environment, and returns a wrapper `pass`. -2. The wrapper `pass` is called with `(2)`: it takes previous args (`1`), concatenates them with what it got `(2)` and calls `curried(1, 2)` with them together. As the argument count is still less than 3, `curry` returns `pass`. -3. The wrapper `pass` is called again with `(3)`, for the next call `pass(3)` takes previous args (`1`, `2`) and adds `3` to them, making the call `curried(1, 2, 3)` -- there are `3` arguments at last, they are given to the original function. +1. The first call `curried(1)` returns a new bounded `curried` with `1` as pre-specified argument. +2. The bounded `curried` is called with `(2)`: it takes previous args (`1`) due to bind, and new leading argument `(2)` and calls `curried(2)`. As the argument count is still less than 3, `curry` returns new bounded `curried` with (`1`, `2`) as pre-specified arguments. +3. The bounded `curried` is called again with `(3)`, for the next call `curried(3)` takes previous args (`1`, `2`) and new leading argument `3`, making the call `curried(3)` -- there are `3` arguments at last, they are given to the original function. If that's still not obvious, just trace the calls sequence in your mind or on paper. From 997f392f7443fe8c94722fe9f440b7b717b13272 Mon Sep 17 00:00:00 2001 From: Lakshya Thakur Date: Sat, 9 Jan 2021 17:40:25 +0530 Subject: [PATCH 2/2] Add the (2) point reference --- 1-js/99-js-misc/03-currying-partials/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/99-js-misc/03-currying-partials/article.md b/1-js/99-js-misc/03-currying-partials/article.md index 2f91197f..0a46f272 100644 --- a/1-js/99-js-misc/03-currying-partials/article.md +++ b/1-js/99-js-misc/03-currying-partials/article.md @@ -150,7 +150,7 @@ The result of `curry(func)` call is the wrapper `curried` that looks like this: function curried(...args) { if (args.length >= func.length) { // (1) return func.apply(this, args); - } else return curried.bind(this, ...args); + } else return curried.bind(this, ...args); // (2) }; ```