- Notifications
You must be signed in to change notification settings - Fork179
Currying#257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Merged
tarasyyyk merged 5 commits intojavascript-tutorial:masterfromAntonBurchak:translations/curryingJan 14, 2022
Uh oh!
There was an error while loading.Please reload this page.
Merged
Currying#257
Changes fromall commits
Commits
Show all changes
5 commits Select commitHold shift + click to select a range
833a6cd
Finished translate "Dynamic imports" article
b4158fc
Revert "Finished translate "Dynamic imports" article"
7fcc037
Finished translations of Currying
AntonBurchak920fad6
Apply suggestions from code review
tarasyyyk4b06c39
Small fixes to translation
tarasyyykFile filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
116 changes: 63 additions & 53 deletions1-js/99-js-misc/03-currying-partials/article.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -3,21 +3,21 @@ libs: | ||
--- | ||
#Каррінг | ||
[Каррінг](https://en.wikipedia.org/wiki/Currying)просунута техніка для роботи з функціями. Вона використовується не лише в JavaScript,але і в інших мовах програмування. | ||
Каррінг — це трансформація функцій таким чином, щоб вони приймали аргументи не як `f(a, b, c)`, а як`f(a)(b)(c)`. | ||
Каррінг не викликає функцію. Він просто трансформує її. | ||
Давайте спочатку подивимося на приклад, щоб краще зрозуміти, про що йде мова, а потім на практичне застосування каррінгу. | ||
Створимо допоміжну функцію`curry(f)`, яка виконує каррінг функції`f` з двома аргументами. Інакше кажучи, функція`curry(f)`трансформує`f(a, b)`в`f(a)(b)`. | ||
```js run | ||
*!* | ||
function curry(f) { // curry(f)виконує каррінг | ||
return function(a) { | ||
return function(b) { | ||
return f(a, b); | ||
@@ -26,7 +26,7 @@ function curry(f) { // curry(f) does the currying transform | ||
} | ||
*/!* | ||
//використання | ||
function sum(a, b) { | ||
return a + b; | ||
} | ||
@@ -36,84 +36,84 @@ let curriedSum = curry(sum); | ||
alert( curriedSum(1)(2) ); // 3 | ||
``` | ||
Як ви бачите, реалізація доволі проста: це дві обгортки. | ||
-Результат`curry(func)`— обгортка `function(a)`. | ||
-Коли функція викликається як `sum(1)`,аргумент зберігається в лексичному середовищі і повертається нова обгортка `function(b)`. | ||
-Далі вже ця обгортка викликається з аргументом 2 і передає виклик до оригінальної функції `sum`. | ||
Більш просунуті реалізації каррінгу, як наприклад [_.curry](https://lodash.com/docs#curry)із бібліотеки lodash, повертають обгортку, яка дозволяє запустити функцію як звичайним способом, так і частково: | ||
```js run | ||
function sum(a, b) { | ||
return a + b; | ||
} | ||
let curriedSum = _.curry(sum); //використовуємо _.curryіз бібліотеки lodash | ||
alert( curriedSum(1, 2) ); // 3,можна викликати як зазвичай | ||
alert( curriedSum(1)(2) ); // 3,а можна частково | ||
``` | ||
##Каррінг? Навіщо? | ||
Щоб зрозуміти користь від каррінгу, нам безперечно потрібний приклад з реального життя. | ||
Наприклад, у нас є функція логування `log(date, importance, message)`, яка форматує і виводить інформацію. У реальних проектах у таких функцій є багато корисних можливостей, наприклад, посилати інформацію по мережі, тут для простоти використаний `alert`: | ||
```js | ||
function log(date, importance, message) { | ||
alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`); | ||
} | ||
``` | ||
А зараз давайте застосуємо каррінг! | ||
```js | ||
log = _.curry(log); | ||
``` | ||
Після цього `log`продовжує працювати нормально: | ||
```js | ||
log(new Date(), "DEBUG", "some debug"); // log(a, b, c) | ||
``` | ||
...Але також працює варіант з каррінгом: | ||
```js | ||
log(new Date())("DEBUG")("some debug"); // log(a)(b)(c) | ||
``` | ||
Давайте зробимо зручну функцію для логів з поточним часом: | ||
```js | ||
// logNowбуде частковим застосуванням функціїlogз фіксованим першим аргументом | ||
let logNow = log(new Date()); | ||
//використаємо її | ||
logNow("INFO", "message"); // [HH:mm] INFO message | ||
``` | ||
Тепер `logNow`- це`log`з фіксованим першим аргументом, інакше кажучи, "частково застосована" або "часткова" функція. | ||
Ми можемо піти далі і зробити зручну функцію для саме налагоджувальних логів з поточним часом: | ||
```js | ||
let debugNow = logNow("DEBUG"); | ||
debugNow("message"); // [HH:mm] DEBUG message | ||
``` | ||
Отже: | ||
1.Ми нічого не втратили після каррінгу: `log`все так само можна викликати нормально. | ||
2.Ми можемо легко створювати частково застосовані функції, як зробили для логів з поточним часом. | ||
##Просунута реалізація каррінгу | ||
У разі, якщо вам цікаві деталі, ось "просунута" реалізація каррінгу для функцій з множиною аргументів, яку ми могли б використати вище. | ||
Вона дуже коротка: | ||
```js | ||
function curry(func) { | ||
@@ -131,7 +131,7 @@ function curry(func) { | ||
} | ||
``` | ||
Приклад використання: | ||
```js | ||
function sum(a, b, c) { | ||
@@ -140,17 +140,17 @@ function sum(a, b, c) { | ||
let curriedSum = curry(sum); | ||
alert( curriedSum(1, 2, 3) ); // 6,все ще можна викликати нормально | ||
alert( curriedSum(1)(2,3) ); // 6,каррінг першого аргументу | ||
alert( curriedSum(1)(2)(3) ); // 6,повний каррінг | ||
``` | ||
Нова функція `curry`виглядає складною, але насправді її легко зрозуміти. | ||
Результат виклику`curry(func)`- це обгортка`curried`, яка виглядає так: | ||
```js | ||
// func- функція, яку ми трансформуємо | ||
function curried(...args) { | ||
if (args.length >= func.length) { // (1) | ||
return func.apply(this, args); | ||
@@ -162,27 +162,37 @@ function curried(...args) { | ||
}; | ||
``` | ||
Коли ми запускаємо її, є дві гілки виконання`if`: | ||
1.Якщо кількість переданих`args`дорівнює або більше, ніж вказано у визначенні початковій функції `(func.length)`, то викликаємо її за допомогою`func.apply`. | ||
2.Часткове застосування: інакше`func`не викликається відразу. Замість цього, повертається інша обгортка `pass`, яка знову застосує `curried`, передавши попередні аргументи разом з новими. | ||
Потім при новому виклику ми знову отримаємо або нове часткове застосування (якщо аргументів недостатньо) або, нарешті, результат. | ||
Наприклад, давайте подивимося, що станеться у разі `sum(a, b, c)`. У неї три аргументи, так що `sum.length = 3`. | ||
Для виклику `curried(1)(2)(3)`: | ||
tarasyyyk marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
1. Перший виклик `curried(1)` запам’ятовує `1` у своєму лексичному середовищі і повертає обгортку `pass`. | ||
2. Обгортка `pass` викликається з `(2)`: вона бере попередні аргументи (`1`), об’єднує їх з тим, що отримала сама `(2)` і викликає `curried(1, 2)` з усіма аргументами. Оскільки число аргументів все ще менше за `3`, `curry` повертає `pass`. | ||
3. Обгортка `pass` викликається знову з `(3)`. Для наступного виклику `pass(3)` бере попередні аргументи `(1, 2)` і додає до них `3`, викликаючи `curried(1, 2, 3)` - нарешті 3 аргументи, і вони передаються оригінальній функції. | ||
Якщо все ще не зрозуміло, просто розпишіть послідовність викликів на папері. | ||
```smart header="Тільки функції з фіксованою кількістю аргументів" | ||
Для каррінгу потрібна функція з фіксованою кількістю аргументів. | ||
З функцію, яка використовує залишкові параметри, типу `f(...args)`, каррінгу не підлягає. | ||
``` | ||
```smart header="Трохи більше, ніж каррінг" | ||
За визначенням, каррінг повинен перетворювати `sum(a, b, c)`на `sum(a)(b)(c)`. | ||
Але, як було описано, більшість реалізацій каррінгу в JavaScript більш просунута: вони також залишають варіант виклику функції з декількома аргументами. | ||
``` | ||
##Підсумки | ||
*Каррінг* - це трансформація, яка перетворює виклик`f(a, b,c)`на`f(a)(b)(c)`.УJavaScriptреалізація зазвичай дозволяє викликати функцію обома варіантами: або нормально, або повертає частково застосовану функцію, якщо недостатня кількість аргументів. | ||
Каррінг дозволяє легко отримувати часткові функції. Як ми бачили в прикладах з логами: універсальна функція`log(date, importance, message)`після каррінгу повертає нам частково застосовану функцію, коли викликається з одним аргументом, як`log(date)` або двома аргументами, як `log(date, importance)`. |
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.