diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..1831a54 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,56 @@ +name: build + +on: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-22.04 + steps: + - name: Checkout source code + uses: actions/checkout@v2.3.1 + + - name: Install Calibre + run: | + wget -nv -O- https://download.calibre-ebook.com/linux-installer.sh | sh /dev/stdin + mkdir -p ~/.local/bin + ln -s /opt/calibre/calibre ~/.local/bin/calibre + ln -s /opt/calibre/ebook-convert ~/.local/bin/ebook-convert + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: 10.22.1 + + - name: Setup gitbook + run: | + npm install + npm run setup + - name: Generate PDF + run: | + npm run generate-pdf + mv book.pdf mostly-adequate-guide-to-functional-programming.pdf + - name: Generate EPUB + run: | + npm run generate-epub + mv book.epub mostly-adequate-guide-to-functional-programming.epub + - uses: actions/upload-artifact@v2 + with: + name: PDF + path: mostly-adequate-guide-to-functional-programming.pdf + + - uses: actions/upload-artifact@v2 + with: + name: EPUB + path: mostly-adequate-guide-to-functional-programming.epub + + - run: echo "::set-output name=ID::$(git describe --tags --always)" + id: release-id + + - uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ steps.release-id.outputs.ID }} + files: | + mostly-adequate-guide-to-functional-programming.pdf + mostly-adequate-guide-to-functional-programming.epub \ No newline at end of file diff --git a/SUMMARY-en.md b/SUMMARY-en.md new file mode 100644 index 0000000..8b014ce --- /dev/null +++ b/SUMMARY-en.md @@ -0,0 +1,148 @@ +# Summary + +* [Chapter 01: What Ever Are We Doing?](ch01.md) + * [Introductions](ch01.md#introductions) + * [A Brief Encounter](ch01.md#a-brief-encounter) +* [Chapter 02: First Class Functions](ch02.md) + * [A Quick Review](ch02.md#a-quick-review) + * [Why Favor First Class?](ch02.md#why-favor-first-class) +* [Chapter 03: Pure Happiness with Pure Functions](ch03.md) + * [Oh to Be Pure Again](ch03.md#oh-to-be-pure-again) + * [Side Effects May Include...](ch03.md#side-effects-may-include) + * [8th Grade Math](ch03.md#8th-grade-math) + * [The Case for Purity](ch03.md#the-case-for-purity) + * [In Summary](ch03.md#in-summary) +* [Chapter 04: Currying](ch04.md) + * [Can't Live If Livin' Is without You](ch04.md#cant-live-if-livin-is-without-you) + * [More Than a Pun / Special Sauce](ch04.md#more-than-a-pun--special-sauce) + * [In Summary](ch04.md#in-summary) + * [Exercises](ch04.md#exercises) +* [Chapter 05: Coding by Composing](ch05.md) + * [Functional Husbandry](ch05.md#functional-husbandry) + * [Pointfree](ch05.md#pointfree) + * [Debugging](ch05.md#debugging) + * [Category Theory](ch05.md#category-theory) + * [In Summary](ch05.md#in-summary) + * [Exercises](ch05.md#exercises) +* [Chapter 06: Example Application](ch06.md) + * [Declarative Coding](ch06.md#declarative-coding) + * [A Flickr of Functional Programming](ch06.md#a-flickr-of-functional-programming) + * [A Principled Refactor](ch06.md#a-principled-refactor) + * [In Summary](ch06.md#in-summary) +* [Chapter 07: Hindley-Milner and Me](ch07.md) + * [What's Your Type?](ch07.md#whats-your-type) + * [Tales from the Cryptic](ch07.md#tales-from-the-cryptic) + * [Narrowing the Possibility](ch07.md#narrowing-the-possibility) + * [Free as in Theorem](ch07.md#free-as-in-theorem) + * [Constraints](ch07.md#constraints) + * [In Summary](ch07.md#in-summary) +* [Chapter 08: Tupperware](ch08.md) + * [The Mighty Container](ch08.md#the-mighty-container) + * [My First Functor](ch08.md#my-first-functor) + * [Schrödinger's Maybe](ch08.md#schrödingers-maybe) + * [Use Cases](ch08.md#use-cases) + * [Releasing the Value](ch08.md#releasing-the-value) + * [Pure Error Handling](ch08.md#pure-error-handling) + * [Old McDonald Had Effects...](ch08.md#old-mcdonald-had-effects) + * [Asynchronous Tasks](ch08.md#asynchronous-tasks) + * [A Spot of Theory](ch08.md#a-spot-of-theory) + * [In Summary](ch08.md#in-summary) + * [Exercises](ch08.md#exercises) +* [Chapter 09: Monadic Onions](ch09.md) + * [Pointy Functor Factory](ch09.md#pointy-functor-factory) + * [Mixing Metaphors](ch09.md#mixing-metaphors) + * [My Chain Hits My Chest](ch09.md#my-chain-hits-my-chest) + * [Power Trip](ch09.md#power-trip) + * [Theory](ch09.md#theory) + * [In Summary](ch09.md#in-summary) + * [Exercises](ch09.md#exercises) +* [Chapter 10: Applicative Functors](ch10.md) + * [Applying Applicatives](ch10.md#applying-applicatives) + * [Ships in Bottles](ch10.md#ships-in-bottles) + * [Coordination Motivation](ch10.md#coordination-motivation) + * [Bro, Do You Even Lift?](ch10.md#bro-do-you-even-lift) + * [Operators](ch10.md#operators) + * [Free Can Openers](ch10.md#free-can-openers) + * [Laws](ch10.md#laws) + * [In Summary](ch10.md#in-summary) + * [Exercises](ch10.md#exercises) +* [Chapter 11: Transform Again, Naturally](ch11.md) + * [Curse This Nest](ch11.md#curse-this-nest) + * [A Situational Comedy](ch11.md#a-situational-comedy) + * [All Natural](ch11.md#all-natural) + * [Principled Type Conversions](ch11.md#principled-type-conversions) + * [Feature Envy](ch11.md#feature-envy) + * [Isomorphic JavaScript](ch11.md#isomorphic-javascript) + * [A Broader Definition](ch11.md#a-broader-definition) + * [One Nesting Solution](ch11.md#one-nesting-solution) + * [In Summary](ch11.md#in-summary) + * [Exercises](ch11.md#exercises) +* [Chapter 12: Traversing the Stone](ch12.md) + * [Types n' Types](ch12.md#types-n-types) + * [Type Feng Shui](ch12.md#type-feng-shui) + * [Effect Assortment](ch12.md#effect-assortment) + * [Waltz of the Types](ch12.md#waltz-of-the-types) + * [No Law and Order](ch12.md#no-law-and-order) + * [In Summary](ch12.md#in-summary) + * [Exercises](ch12.md#exercises) +* [Chapter 13: Monoids bring it all together](ch13.md) + * [Wild combination](ch13.md#wild-combination) + * [Abstracting addition](ch13.md#abstracting-addition) + * [All my favourite functors are semigroups](ch13.md#all-my-favourite-functors-are-semigroups) + * [Monoids for nothing](ch13.md#monoids-for-nothing) + * [Folding down the house](ch13.md#folding-down-the-house) + * [Not quite a monoid](ch13.md#not-quite-a-monoid) + * [Grand unifying theory](ch13.md#grand-unifying-theory) + * [In Summary](ch13.md#in-summary) + * [Exercises](ch13.md#exercises) +* [Appendix A: Essential Functions Support](appendix_a.md) + * [always](appendix_a.md#always) + * [compose](appendix_a.md#compose) + * [curry](appendix_a.md#curry) + * [either](appendix_a.md#either) + * [identity](appendix_a.md#identity) + * [inspect](appendix_a.md#inspect) + * [left](appendix_a.md#left) + * [liftA\*](appendix_a.md#lifta) + * [maybe](appendix_a.md#maybe) + * [nothing](appendix_a.md#nothing) + * [reject](appendix_a.md#reject) +* [Appendix B: Algebraic Structures Support](appendix_b.md) + * [Compose](appendix_b.md#compose) + * [Either](appendix_b.md#either) + * [Identity](appendix_b.md#identity) + * [IO](appendix_b.md#io) + * [List](appendix_b.md#list) + * [Map](appendix_b.md#map) + * [Maybe](appendix_b.md#maybe) + * [Task](appendix_b.md#task) +* [Appendix C: Pointfree Utilities](appendix_c.md) + * [add](appendix_c.md#add) + * [append](appendix_c.md#append) + * [chain](appendix_c.md#chain) + * [concat](appendix_c.md#concat) + * [eq](appendix_c.md#eq) + * [filter](appendix_c.md#filter) + * [flip](appendix_c.md#flip) + * [forEach](appendix_c.md#foreach) + * [head](appendix_c.md#head) + * [intercalate](appendix_c.md#intercalate) + * [join](appendix_c.md#join) + * [last](appendix_c.md#last) + * [map](appendix_c.md#map) + * [match](appendix_c.md#match) + * [prop](appendix_c.md#prop) + * [reduce](appendix_c.md#reduce) + * [replace](appendix_c.md#replace) + * [safeHead](appendix_c.md#safehead) + * [safeLast](appendix_c.md#safelast) + * [safeProp](appendix_c.md#safeprop) + * [sequence](appendix_c.md#sequence) + * [sortBy](appendix_c.md#sortby) + * [split](appendix_c.md#split) + * [take](appendix_c.md#take) + * [toLowerCase](appendix_c.md#tolowercase) + * [toString](appendix_c.md#tostring) + * [toUpperCase](appendix_c.md#touppercase) + * [traverse](appendix_c.md#traverse) + * [unsafePerformIO](appendix_c.md#unsafeperformio) diff --git a/SUMMARY-ru.md b/SUMMARY-ru.md deleted file mode 100644 index dc6b0e4..0000000 --- a/SUMMARY-ru.md +++ /dev/null @@ -1,146 +0,0 @@ -# Summary - -* [Глава 01: Чем предстоит заниматься](ch01-ru.md) - * [Вступление](ch01-ru.md#вступление) - * [О чем пойдет речь?](ch01-ru.md#о-чем-пойдет-речь) -* [Глава 02: Функции первого класса](ch02-ru.md) - * [Краткий обзор](ch02-ru.md#краткий-обзор) - * [Зачем отдавать предпочтение первому классу?](ch02-ru.md#зачем-отдавать-предпочтение-первому-классу) -* [Глава 03: Чистое счастье с Чистыми функциями](ch03-ru.md) - * [Как же хорошо снова быть чистым](ch03-ru.md#как-же-хорошо-снова-быть-чистым) - * [Побочные эффекты могут включать...](ch03-ru.md#побочные-эффекты-могут-включать) - * [Математика 8-го класса](ch03-ru.md#математика-8-го-класса) - * [Доводы в пользу чистоты](ch03-ru.md#доводы-в-пользу-чистоты) - * [Итог](ch03-ru.md#итог) -* [Глава 04: Каррирование](ch04-ru.md) - * [Без тебя мне жизнь не мила](ch04-ru.md#без-тебя-мне-жизнь-не-мила) - * [Больше, чем «приправа»](ch04-ru.md#больше-чем-приправа) - * [Итог](ch04-ru.md#итог) -* [Глава 05: Использование композиции](ch05-ru.md) - * [Скрещивание функций](ch05-ru.md#скрещивание-функций) - * [Бесточечный стиль](ch05-ru.md#бесточечный-стиль) - * [Дебаггинг](ch05-ru.md#дебаггинг) - * [Теория категорий](ch05-ru.md#теория-категорий) - * [Итог](ch05-ru.md#итог) -* [Глава 06: Пример приложения](ch06-ru.md) - * [Декларативное программирование](ch06-ru.md#декларативное-программирование) - * [Flickr, написанный в функциональном стиле](ch06-ru.md#flickr-в-функциональном-стиле) - * [Рефакторинг, обоснованный принципами](ch06-ru.md#рефакторинг-обоснованный-принципами) - * [Итог](ch06-ru.md#итог) -* [Глава 07: Хиндли-Милнер и Я](ch07-ru.md) - * [Каков твой тип?](ch07-ru.md#каков-твой-тип) - * [Байки из cкрипта](ch07-ru.md#байки-из-cкрипта) - * [Сужение возможностей](ch07-ru.md#сужение-возможностей) - * [Бесплатно, как в теореме](ch07-ru.md#бесплатно-как-в-теореме) - * [Ограничения для типов](ch07-ru.md#ограничения-для-типов) - * [Итог](ch07-ru.md#итог) -* [Глава 08: Контейнеры](ch08-ru.md) - * [Могучий контейнер](ch08-ru.md#могучий-контейнер) - * [Мой первый функтор](ch08-ru.md#мой-первый-функтор) - * [Maybe Шрёдингера](ch08-ru.md#maybe-шрёдингера) - * [Примеры использования](ch08-ru.md#примеры-использования) - * [Извлечение значения](ch08-ru.md#извлечение-значения) - * [Чистая обработка ошибок](ch08-ru.md#чистая-обработка-ошибок) - * [Эффект домино](ch08-ru.md#эффект-домино) - * [Асинхронные задачи](ch08-ru.md#асинхронные-задачи) - * [Немного теории](ch08-ru.md#немного-теории) - * [Итог](ch08-ru.md#итог) - * [Упражнения](ch08-ru.md#упражнения) -* [Глава 09: Монадические луковицы](ch09-ru.md) - * [Функторы и минимальный контекст](ch09-ru.md#функторы-и-минимальный-контекст) - * [Соединяем метафоры](ch09-ru.md#соединяем-метафоры) - * [Цепочки монадических вычислений](ch09-ru.md#цепочки-монадических-вычислений) - * [В полную силу](ch09-ru.md#в-полную-силу) - * [Теория](ch09-ru.md#теория) - * [Итог](ch09-ru.md#итог) - * [Упражнения](ch09-ru.md#упражнения) -* [Глава 10: Аппликативные функторы](ch10-ru.md) - * [Аппликативная аппликация](ch10-ru.md#аппликативная-аппликация) - * [Корабли в бутылках](ch10-ru.md#корабли-в-бутылках) - * [Порядок выполнения](ch10-ru.md#порядок-выполнения) - * [Сколько жмёшь, братишка?](ch10-ru.md#сколько-жмёшь-братишка) - * [Инфиксные функции](ch10-ru.md#инфиксные-функции) - * [Бесплатные открывашки](ch10-ru.md#бесплатные-открывашки) - * [Законы](ch10-ru.md#законы) - * [Итог](ch10-ru.md#итог) - * [Упражнения](ch10-ru.md#упражнения) -* [Глава 11: Опять преобразования, естественно](ch11-ru.md) - * [Вложенные проблемы](ch11-ru.md#вложенные-проблемы) - * [Ситуационная комедия](ch11-ru.md#ситуационная-комедия) - * [Всё натуральное](ch11-ru.md#всё-натуральное) - * [Обоснованные преобразования типов](ch11-ru.md#обоснованные-преобразования-типов) - * [Успокаиваем функциональную зависть](ch11-ru.md#успокаиваем-функциональную-зависть) - * [Изоморфный JavaScript](ch11-ru.md#изоморфный-javascript) - * [Расширяем определение](ch11-ru.md#расширяем-определение) - * [История одной вложенности](ch11-ru.md#история-одной-вложенности) - * [Итог](ch11-ru.md#итог) - * [Упражнения](ch11-ru.md#упражнения) -* [Глава 12: Проходя сквозь препятствия](ch12-ru.md) - * [Типы застряли друг в друге](ch12-ru.md#типы-застряли-друг-в-друге) - * [Типовый Фэн-шуй](ch12-ru.md#типовый-фэн-шуй) - * [Ассортимент эффектов](ch12-ru.md#ассортимент-эффектов) - * [Вальс типов](ch12-ru.md#вальс-типов) - * [Законы и архитектурный беспорядок](ch12-ru.md#законы-и-архитектурный-беспорядок) - * [Итог](ch12-ru.md#итог) - * [Упражнения](ch12-ru.md#упражнения) -* [Chapter 13: Monoids bring it all together](ch13-ru.md) - * [Wild combination](ch13-ru.md#wild-combination) - * [Abstracting addition](ch13-ru.md#abstracting-addition) - * [All my favourite functors are semigroups](ch13-ru.md#all-my-favourite-functors-are-semigroups) - * [Monoids for nothing](ch13-ru.md#monoids-for-nothing) - * [Folding down the house](ch13-ru.md#folding-down-the-house) - * [Not quite a monoid](ch13-ru.md#not-quite-a-monoid) - * [Grand unifying theory](ch13-ru.md#grand-unifying-theory) - * [In Summary](ch13-ru.md#in-summary) - * [Exercises](ch13-ru.md#exercises) -* [Appendix A: Essential Functions Support](appendix_a-ru.md) - * [always](appendix_a-ru.md#always) - * [compose](appendix_a-ru.md#compose) - * [curry](appendix_a-ru.md#curry) - * [either](appendix_a-ru.md#either) - * [identity](appendix_a-ru.md#identity) - * [inspect](appendix_a-ru.md#inspect) - * [left](appendix_a-ru.md#left) - * [liftA\*](appendix_a-ru.md#lifta) - * [maybe](appendix_a-ru.md#maybe) - * [nothing](appendix_a-ru.md#nothing) - * [reject](appendix_a-ru.md#reject) -* [Appendix B: Algebraic Structures Support](appendix_b-ru.md) - * [Compose](appendix_b-ru.md#compose) - * [Either](appendix_b-ru.md#either) - * [Identity](appendix_b-ru.md#identity) - * [IO](appendix_b-ru.md#io) - * [List](appendix_b-ru.md#list) - * [Map](appendix_b-ru.md#map) - * [Maybe](appendix_b-ru.md#maybe) - * [Task](appendix_b-ru.md#task) -* [Appendix C: Pointfree Utilities](appendix_c-ru.md) - * [add](appendix_c-ru.md#add) - * [append](appendix_c-ru.md#append) - * [chain](appendix_c-ru.md#chain) - * [concat](appendix_c-ru.md#concat) - * [eq](appendix_c-ru.md#eq) - * [filter](appendix_c-ru.md#filter) - * [flip](appendix_c-ru.md#flip) - * [forEach](appendix_c-ru.md#foreach) - * [head](appendix_c-ru.md#head) - * [intercalate](appendix_c-ru.md#intercalate) - * [join](appendix_c-ru.md#join) - * [last](appendix_c-ru.md#last) - * [map](appendix_c-ru.md#map) - * [match](appendix_c-ru.md#match) - * [prop](appendix_c-ru.md#prop) - * [reduce](appendix_c-ru.md#reduce) - * [replace](appendix_c-ru.md#replace) - * [safeHead](appendix_c-ru.md#safehead) - * [safeLast](appendix_c-ru.md#safelast) - * [safeProp](appendix_c-ru.md#safeprop) - * [sequence](appendix_c-ru.md#sequence) - * [sortBy](appendix_c-ru.md#sortby) - * [split](appendix_c-ru.md#split) - * [take](appendix_c-ru.md#take) - * [toLowerCase](appendix_c-ru.md#tolowercase) - * [toString](appendix_c-ru.md#tostring) - * [toUpperCase](appendix_c-ru.md#touppercase) - * [traverse](appendix_c-ru.md#traverse) - * [unsafePerformIO](appendix_c-ru.md#unsafeperformio) diff --git a/SUMMARY.md b/SUMMARY.md index 8b014ce..9aa699a 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -1,148 +1,146 @@ # Summary -* [Chapter 01: What Ever Are We Doing?](ch01.md) - * [Introductions](ch01.md#introductions) - * [A Brief Encounter](ch01.md#a-brief-encounter) -* [Chapter 02: First Class Functions](ch02.md) - * [A Quick Review](ch02.md#a-quick-review) - * [Why Favor First Class?](ch02.md#why-favor-first-class) -* [Chapter 03: Pure Happiness with Pure Functions](ch03.md) - * [Oh to Be Pure Again](ch03.md#oh-to-be-pure-again) - * [Side Effects May Include...](ch03.md#side-effects-may-include) - * [8th Grade Math](ch03.md#8th-grade-math) - * [The Case for Purity](ch03.md#the-case-for-purity) - * [In Summary](ch03.md#in-summary) -* [Chapter 04: Currying](ch04.md) - * [Can't Live If Livin' Is without You](ch04.md#cant-live-if-livin-is-without-you) - * [More Than a Pun / Special Sauce](ch04.md#more-than-a-pun--special-sauce) - * [In Summary](ch04.md#in-summary) - * [Exercises](ch04.md#exercises) -* [Chapter 05: Coding by Composing](ch05.md) - * [Functional Husbandry](ch05.md#functional-husbandry) - * [Pointfree](ch05.md#pointfree) - * [Debugging](ch05.md#debugging) - * [Category Theory](ch05.md#category-theory) - * [In Summary](ch05.md#in-summary) - * [Exercises](ch05.md#exercises) -* [Chapter 06: Example Application](ch06.md) - * [Declarative Coding](ch06.md#declarative-coding) - * [A Flickr of Functional Programming](ch06.md#a-flickr-of-functional-programming) - * [A Principled Refactor](ch06.md#a-principled-refactor) - * [In Summary](ch06.md#in-summary) -* [Chapter 07: Hindley-Milner and Me](ch07.md) - * [What's Your Type?](ch07.md#whats-your-type) - * [Tales from the Cryptic](ch07.md#tales-from-the-cryptic) - * [Narrowing the Possibility](ch07.md#narrowing-the-possibility) - * [Free as in Theorem](ch07.md#free-as-in-theorem) - * [Constraints](ch07.md#constraints) - * [In Summary](ch07.md#in-summary) -* [Chapter 08: Tupperware](ch08.md) - * [The Mighty Container](ch08.md#the-mighty-container) - * [My First Functor](ch08.md#my-first-functor) - * [Schrödinger's Maybe](ch08.md#schrödingers-maybe) - * [Use Cases](ch08.md#use-cases) - * [Releasing the Value](ch08.md#releasing-the-value) - * [Pure Error Handling](ch08.md#pure-error-handling) - * [Old McDonald Had Effects...](ch08.md#old-mcdonald-had-effects) - * [Asynchronous Tasks](ch08.md#asynchronous-tasks) - * [A Spot of Theory](ch08.md#a-spot-of-theory) - * [In Summary](ch08.md#in-summary) - * [Exercises](ch08.md#exercises) -* [Chapter 09: Monadic Onions](ch09.md) - * [Pointy Functor Factory](ch09.md#pointy-functor-factory) - * [Mixing Metaphors](ch09.md#mixing-metaphors) - * [My Chain Hits My Chest](ch09.md#my-chain-hits-my-chest) - * [Power Trip](ch09.md#power-trip) - * [Theory](ch09.md#theory) - * [In Summary](ch09.md#in-summary) - * [Exercises](ch09.md#exercises) -* [Chapter 10: Applicative Functors](ch10.md) - * [Applying Applicatives](ch10.md#applying-applicatives) - * [Ships in Bottles](ch10.md#ships-in-bottles) - * [Coordination Motivation](ch10.md#coordination-motivation) - * [Bro, Do You Even Lift?](ch10.md#bro-do-you-even-lift) - * [Operators](ch10.md#operators) - * [Free Can Openers](ch10.md#free-can-openers) - * [Laws](ch10.md#laws) - * [In Summary](ch10.md#in-summary) - * [Exercises](ch10.md#exercises) -* [Chapter 11: Transform Again, Naturally](ch11.md) - * [Curse This Nest](ch11.md#curse-this-nest) - * [A Situational Comedy](ch11.md#a-situational-comedy) - * [All Natural](ch11.md#all-natural) - * [Principled Type Conversions](ch11.md#principled-type-conversions) - * [Feature Envy](ch11.md#feature-envy) - * [Isomorphic JavaScript](ch11.md#isomorphic-javascript) - * [A Broader Definition](ch11.md#a-broader-definition) - * [One Nesting Solution](ch11.md#one-nesting-solution) - * [In Summary](ch11.md#in-summary) - * [Exercises](ch11.md#exercises) -* [Chapter 12: Traversing the Stone](ch12.md) - * [Types n' Types](ch12.md#types-n-types) - * [Type Feng Shui](ch12.md#type-feng-shui) - * [Effect Assortment](ch12.md#effect-assortment) - * [Waltz of the Types](ch12.md#waltz-of-the-types) - * [No Law and Order](ch12.md#no-law-and-order) - * [In Summary](ch12.md#in-summary) - * [Exercises](ch12.md#exercises) -* [Chapter 13: Monoids bring it all together](ch13.md) - * [Wild combination](ch13.md#wild-combination) - * [Abstracting addition](ch13.md#abstracting-addition) - * [All my favourite functors are semigroups](ch13.md#all-my-favourite-functors-are-semigroups) - * [Monoids for nothing](ch13.md#monoids-for-nothing) - * [Folding down the house](ch13.md#folding-down-the-house) - * [Not quite a monoid](ch13.md#not-quite-a-monoid) - * [Grand unifying theory](ch13.md#grand-unifying-theory) - * [In Summary](ch13.md#in-summary) - * [Exercises](ch13.md#exercises) -* [Appendix A: Essential Functions Support](appendix_a.md) - * [always](appendix_a.md#always) - * [compose](appendix_a.md#compose) - * [curry](appendix_a.md#curry) - * [either](appendix_a.md#either) - * [identity](appendix_a.md#identity) - * [inspect](appendix_a.md#inspect) - * [left](appendix_a.md#left) - * [liftA\*](appendix_a.md#lifta) - * [maybe](appendix_a.md#maybe) - * [nothing](appendix_a.md#nothing) - * [reject](appendix_a.md#reject) -* [Appendix B: Algebraic Structures Support](appendix_b.md) - * [Compose](appendix_b.md#compose) - * [Either](appendix_b.md#either) - * [Identity](appendix_b.md#identity) - * [IO](appendix_b.md#io) - * [List](appendix_b.md#list) - * [Map](appendix_b.md#map) - * [Maybe](appendix_b.md#maybe) - * [Task](appendix_b.md#task) -* [Appendix C: Pointfree Utilities](appendix_c.md) - * [add](appendix_c.md#add) - * [append](appendix_c.md#append) - * [chain](appendix_c.md#chain) - * [concat](appendix_c.md#concat) - * [eq](appendix_c.md#eq) - * [filter](appendix_c.md#filter) - * [flip](appendix_c.md#flip) - * [forEach](appendix_c.md#foreach) - * [head](appendix_c.md#head) - * [intercalate](appendix_c.md#intercalate) - * [join](appendix_c.md#join) - * [last](appendix_c.md#last) - * [map](appendix_c.md#map) - * [match](appendix_c.md#match) - * [prop](appendix_c.md#prop) - * [reduce](appendix_c.md#reduce) - * [replace](appendix_c.md#replace) - * [safeHead](appendix_c.md#safehead) - * [safeLast](appendix_c.md#safelast) - * [safeProp](appendix_c.md#safeprop) - * [sequence](appendix_c.md#sequence) - * [sortBy](appendix_c.md#sortby) - * [split](appendix_c.md#split) - * [take](appendix_c.md#take) - * [toLowerCase](appendix_c.md#tolowercase) - * [toString](appendix_c.md#tostring) - * [toUpperCase](appendix_c.md#touppercase) - * [traverse](appendix_c.md#traverse) - * [unsafePerformIO](appendix_c.md#unsafeperformio) +* [Глава 01: Чем предстоит заниматься](ch01-ru.md) + * [Вступление](ch01-ru.md#вступление) + * [О чем пойдет речь?](ch01-ru.md#о-чем-пойдет-речь) +* [Глава 02: Функции первого класса](ch02-ru.md) + * [Краткий обзор](ch02-ru.md#краткий-обзор) + * [Зачем отдавать предпочтение первому классу?](ch02-ru.md#зачем-отдавать-предпочтение-первому-классу) +* [Глава 03: Чистое счастье с Чистыми функциями](ch03-ru.md) + * [Как же хорошо снова быть чистым](ch03-ru.md#как-же-хорошо-снова-быть-чистым) + * [Побочные эффекты могут включать...](ch03-ru.md#побочные-эффекты-могут-включать) + * [Математика 8-го класса](ch03-ru.md#математика-8-го-класса) + * [Доводы в пользу чистоты](ch03-ru.md#доводы-в-пользу-чистоты) + * [Итог](ch03-ru.md#итог) +* [Глава 04: Каррирование](ch04-ru.md) + * [Без тебя мне жизнь не мила](ch04-ru.md#без-тебя-мне-жизнь-не-мила) + * [Больше, чем «приправа»](ch04-ru.md#больше-чем-приправа) + * [Итог](ch04-ru.md#итог) +* [Глава 05: Использование композиции](ch05-ru.md) + * [Скрещивание функций](ch05-ru.md#скрещивание-функций) + * [Бесточечный стиль](ch05-ru.md#бесточечный-стиль) + * [Дебаггинг](ch05-ru.md#дебаггинг) + * [Теория категорий](ch05-ru.md#теория-категорий) + * [Итог](ch05-ru.md#итог) +* [Глава 06: Пример приложения](ch06-ru.md) + * [Декларативное программирование](ch06-ru.md#декларативное-программирование) + * [Flickr, написанный в функциональном стиле](ch06-ru.md#flickr-в-функциональном-стиле) + * [Рефакторинг, обоснованный принципами](ch06-ru.md#рефакторинг-обоснованный-принципами) + * [Итог](ch06-ru.md#итог) +* [Глава 07: Хиндли-Милнер и Я](ch07-ru.md) + * [Каков твой тип?](ch07-ru.md#каков-твой-тип) + * [Байки из cкрипта](ch07-ru.md#байки-из-cкрипта) + * [Сужение возможностей](ch07-ru.md#сужение-возможностей) + * [Бесплатно, как в теореме](ch07-ru.md#бесплатно-как-в-теореме) + * [Ограничения для типов](ch07-ru.md#ограничения-для-типов) + * [Итог](ch07-ru.md#итог) +* [Глава 08: Контейнеры](ch08-ru.md) + * [Могучий контейнер](ch08-ru.md#могучий-контейнер) + * [Мой первый функтор](ch08-ru.md#мой-первый-функтор) + * [Maybe Шрёдингера](ch08-ru.md#maybe-шрёдингера) + * [Примеры использования](ch08-ru.md#примеры-использования) + * [Извлечение значения](ch08-ru.md#извлечение-значения) + * [Чистая обработка ошибок](ch08-ru.md#чистая-обработка-ошибок) + * [Эффект домино](ch08-ru.md#эффект-домино) + * [Асинхронные задачи](ch08-ru.md#асинхронные-задачи) + * [Немного теории](ch08-ru.md#немного-теории) + * [Итог](ch08-ru.md#итог) + * [Упражнения](ch08-ru.md#упражнения) +* [Глава 09: Монадические луковицы](ch09-ru.md) + * [Функторы и минимальный контекст](ch09-ru.md#функторы-и-минимальный-контекст) + * [Соединяем метафоры](ch09-ru.md#соединяем-метафоры) + * [Цепочки монадических вычислений](ch09-ru.md#цепочки-монадических-вычислений) + * [В полную силу](ch09-ru.md#в-полную-силу) + * [Теория](ch09-ru.md#теория) + * [Итог](ch09-ru.md#итог) + * [Упражнения](ch09-ru.md#упражнения) +* [Глава 10: Аппликативные функторы](ch10-ru.md) + * [Аппликативная аппликация](ch10-ru.md#аппликативная-аппликация) + * [Корабли в бутылках](ch10-ru.md#корабли-в-бутылках) + * [Порядок выполнения](ch10-ru.md#порядок-выполнения) + * [Сколько жмёшь, братишка?](ch10-ru.md#сколько-жмёшь-братишка) + * [Инфиксные функции](ch10-ru.md#инфиксные-функции) + * [Бесплатные открывашки](ch10-ru.md#бесплатные-открывашки) + * [Законы](ch10-ru.md#законы) + * [Итог](ch10-ru.md#итог) + * [Упражнения](ch10-ru.md#упражнения) +* [Глава 11: Опять преобразования, естественно](ch11-ru.md) + * [Вложенные проблемы](ch11-ru.md#вложенные-проблемы) + * [Ситуационная комедия](ch11-ru.md#ситуационная-комедия) + * [Всё натуральное](ch11-ru.md#всё-натуральное) + * [Обоснованные преобразования типов](ch11-ru.md#обоснованные-преобразования-типов) + * [Успокаиваем функциональную зависть](ch11-ru.md#успокаиваем-функциональную-зависть) + * [Изоморфный JavaScript](ch11-ru.md#изоморфный-javascript) + * [Расширяем определение](ch11-ru.md#расширяем-определение) + * [История одной вложенности](ch11-ru.md#история-одной-вложенности) + * [Итог](ch11-ru.md#итог) + * [Упражнения](ch11-ru.md#упражнения) +* [Глава 12: Проходя сквозь препятствия](ch12-ru.md) + * [Типы застряли друг в друге](ch12-ru.md#типы-застряли-друг-в-друге) + * [Типовый Фэн-шуй](ch12-ru.md#типовый-фэн-шуй) + * [Ассортимент эффектов](ch12-ru.md#ассортимент-эффектов) + * [Вальс типов](ch12-ru.md#вальс-типов) + * [Законы и архитектурный беспорядок](ch12-ru.md#законы-и-архитектурный-беспорядок) + * [Итог](ch12-ru.md#итог) + * [Упражнения](ch12-ru.md#упражнения) +* [Глава 13: Моноиды объединяют все вместе](ch13-ru.md) + * [Дикая комбинация](ch13-ru.md#дикая-комбинация) + * [Абстрактное дополнение](ch13-ru.md#абстрактное-дополнение) + * [Все мои любимые функторы являются полугруппами](ch13-ru.md#все-мои-любимые-функторы-являются-полугруппами) + * [Моноиды просто так](ch13-ru.md#моноиды-просто-так) + * [Собираем всё вместе](ch13-ru.md#собираем-всё-вместе) + * [Не совсем моноид](ch13-ru.md#не-совсем-моноид) + * [Великая объединяющая теория](ch13-ru.md#великая-объединяющая-теория) + * [Итог](ch13-ru.md#итог) + * [Упражнения](ch13-ru.md#упражнения) +* [Приложение A: Поддержка основных функций](appendix_a-ru.md) + * [always](appendix_a-ru.md#always) + * [compose](appendix_a-ru.md#compose) + * [curry](appendix_a-ru.md#curry) + * [either](appendix_a-ru.md#either) + * [identity](appendix_a-ru.md#identity) + * [inspect](appendix_a-ru.md#inspect) + * [left](appendix_a-ru.md#left) + * [liftA\*](appendix_a-ru.md#lifta) + * [maybe](appendix_a-ru.md#maybe) + * [nothing](appendix_a-ru.md#nothing) + * [reject](appendix_a-ru.md#reject) +* [Приложение B: Поддержка алгебраических структур](appendix_b-ru.md) + * [Compose](appendix_b-ru.md#compose) + * [Either](appendix_b-ru.md#either) + * [Identity](appendix_b-ru.md#identity) + * [IO](appendix_b-ru.md#io) + * [List](appendix_b-ru.md#list) + * [Map](appendix_b-ru.md#map) + * [Maybe](appendix_b-ru.md#maybe) + * [Task](appendix_b-ru.md#task) +* [Приложение C: Бесконечные утилиты](appendix_c-ru.md) + * [add](appendix_c-ru.md#add) + * [append](appendix_c-ru.md#append) + * [chain](appendix_c-ru.md#chain) + * [concat](appendix_c-ru.md#concat) + * [eq](appendix_c-ru.md#eq) + * [filter](appendix_c-ru.md#filter) + * [flip](appendix_c-ru.md#flip) + * [forEach](appendix_c-ru.md#foreach) + * [head](appendix_c-ru.md#head) + * [intercalate](appendix_c-ru.md#intercalate) + * [join](appendix_c-ru.md#join) + * [last](appendix_c-ru.md#last) + * [map](appendix_c-ru.md#map) + * [match](appendix_c-ru.md#match) + * [prop](appendix_c-ru.md#prop) + * [reduce](appendix_c-ru.md#reduce) + * [replace](appendix_c-ru.md#replace) + * [safeHead](appendix_c-ru.md#safehead) + * [safeLast](appendix_c-ru.md#safelast) + * [safeProp](appendix_c-ru.md#safeprop) + * [sequence](appendix_c-ru.md#sequence) + * [sortBy](appendix_c-ru.md#sortby) + * [split](appendix_c-ru.md#split) + * [take](appendix_c-ru.md#take) + * [toLowerCase](appendix_c-ru.md#tolowercase) + * [toString](appendix_c-ru.md#tostring) + * [toUpperCase](appendix_c-ru.md#touppercase) + * [traverse](appendix_c-ru.md#traverse) + * [unsafePerformIO](appendix_c-ru.md#unsafeperformio) diff --git a/appendix_a-ru.md b/appendix_a-ru.md index c012c1e..2d9ceb1 100644 --- a/appendix_a-ru.md +++ b/appendix_a-ru.md @@ -1,13 +1,13 @@ -# Appendix A: Essential Functions Support +# Приложение A: Поддержка Основных Функций -In this appendix, you'll find some basic JavaScript implementations of various functions -described in the book. Keep in mind that these implementations may not be the fastest or the -most efficient implementation out there; they *solely serve an educational purpose*. +В этом приложении вы найдете несколько базовых реализаций JavaScript различных функций +описанных в книге. Имейте в виду, что эти реализации могут быть не самыми быстрыми и не самыми эффективными. +они служат исключительно образовательным целям. -In order to find functions that are more production-ready, have a peek at -[ramda](https://ramdajs.com/), [lodash](https://lodash.com/), or [folktale](http://folktale.origamitower.com/). +Чтобы найти функции, более пригодные для использования в производстве, загляните в раздел +[ramda](https://ramdajs.com/), [lodash](https://lodash.com/), или [folktale](http://folktale.origamitower.com/). -Note that some functions also refer to algebraic structures defined in the [Appendix B](./appendix_b-ru.md) +Обратите внимание, что некоторые функции также ссылаются на алгебраические структуры, определенные в [Appendix B](./appendix_b-ru.md) ## always diff --git a/appendix_b-ru.md b/appendix_b-ru.md index 30938cf..8d3c449 100644 --- a/appendix_b-ru.md +++ b/appendix_b-ru.md @@ -1,13 +1,13 @@ -# Appendix B: Algebraic Structures Support +# Приложение B: Поддержка Алгебраических Структур -In this appendix, you'll find some basic JavaScript implementations of various algebraic -structures described in the book. Keep in mind that these implementations may not be the fastest or the -most efficient implementation out there; they *solely serve an educational purpose*. +В этом приложении вы найдете несколько базовых реализаций JavaScript различных алгебраических +структур, описанных в книге. Имейте в виду, что эти реализации могут быть не самыми быстрыми и не самыми эффективными. +самой быстрой или самой эффективной; они служат исключительно образовательным целям. -In order to find structures that are more production-ready, have a peek at [folktale](http://folktale.origamitower.com/) +Чтобы найти структуры, более пригодные для производства, загляните в раздел [folktale](http://folktale.origamitower.com/) or [fantasy-land](https://github.com/fantasyland). -Note that some methods also refer to functions defined in the [Appendix A](./appendix_a-ru.md) +Обратите внимание, что некоторые методы также ссылаются на функции, определенные в [Appendix A](./appendix_a-ru.md) ## Compose diff --git a/appendix_c-ru.md b/appendix_c-ru.md index 5032ccb..0778691 100644 --- a/appendix_c-ru.md +++ b/appendix_c-ru.md @@ -1,14 +1,14 @@ -# Appendix C: Pointfree Utilities +# Приложение C: Бесконечные Утилиты -In this appendix, you'll find pointfree versions of rather classic JavaScript functions -described in the book. All of the following functions are seemingly available in exercises, as -part of the global context. Keep in mind that these implementations may not be the fastest or -the most efficient implementation out there; they *solely serve an educational purpose*. +В этом приложении вы найдете бессмысленные версии довольно классических функций JavaScript +описанных в книге. Все перечисленные ниже функции доступны в упражнениях как +как часть глобального контекста. Имейте в виду, что эти реализации могут быть не самыми быстрыми или +наиболее эффективными; они служат исключительно образовательным целям. -In order to find functions that are more production-ready, have a peek at -[ramda](https://ramdajs.com/), [lodash](https://lodash.com/), or [folktale](http://folktale.origamitower.com/). +Чтобы найти функции, более пригодные для использования в производстве, загляните в раздел +[ramda](https://ramdajs.com/), [lodash](https://lodash.com/), или [folktale](http://folktale.origamitower.com/). -Note that functions refer to the `curry` & `compose` functions defined in [Appendix A](./appendix_a-ru.md) +Обратите внимание, что функции ссылаются на функции `curry` и `compose`, определенные в [Appendix A](./appendix_a-ru.md) ## add diff --git a/ch13-ru.md b/ch13-ru.md index 59ea3a1..7a70dac 100644 --- a/ch13-ru.md +++ b/ch13-ru.md @@ -1,44 +1,44 @@ -# Chapter 13: Monoids bring it all together +# Глава 13: Моноиды объединяют все вместе -## Wild combination +## Дикая комбинация -In this chapter, we will examine *monoids* by way of *semigroup*. *Monoids* are the bubblegum in the hair of mathematical abstraction. They capture an idea that spans multiple disciplines, figuratively and literally bringing them all together. They are the ominous force that connects all that calculates. The oxygen in our code base, the ground on which it runs, quantum entanglement encoded. +В этой главе мы рассмотрим *моноиды* на примере *семигрупп*. *Моноиды* - это жвачка в волосах математической абстракции. Они фиксируют идею, которая охватывает множество дисциплин, образно и буквально объединяя их все вместе. Они - зловещая сила, связывающая все, что вычисляется. Кислород в нашей кодовой базе, земля, на которой она работает, закодированная квантовая запутанность. -*Monoids* are about combination. But what is combination? It can mean so many things from accumulation to concatenation to multiplication to choice, composition, ordering, even evaluation! We'll see many examples here, but we'll only tip-toe on the foothills of monoid mountain. The instances are plentiful and applications vast. The aim of this chapter is to provide a good intuition so you can make some *monoids* of your own. +*Моноиды - это сочетание. Но что такое комбинация? Это может означать так много вещей: от накопления до конкатенации, от умножения до выбора, композиции, упорядочивания, даже оценки! Здесь мы увидим множество примеров, но мы лишь на цыпочках пройдемся по подножию горы моноидов. Примеров много, а приложений - огромное количество. Цель этой главы - дать хорошую интуицию, чтобы вы могли создать несколько собственных *моноидов*. -## Abstracting addition +## Абстрактное дополнение -Addition has some interesting qualities I'd like to discuss. Let's have a look at it through our abstraction goggles. +Сложение обладает некоторыми интересными свойствами, которые я хотел бы обсудить. Давайте посмотрим на него через очки абстракции. -For starters, it's a binary operation, that is, an operation which takes two values and returns a value, all within the same set. +Для начала, это бинарная операция, то есть операция, которая принимает два значения и возвращает одно значение, все в пределах одного набора. ```js -// a binary operation +// бинарный операции 1 + 1 = 2 ``` -See? Two values in the domain, one value in the codomain, all the same set - numbers, as it were. Some might say numbers are "closed under addition", meaning the type won't ever change no matter which ones get tossed into the mix. That means we can chain the operation since the result is always another number: +Видите? Два значения в домене, одно значение в кодомене, все это один и тот же набор - числа, так сказать. Кто-то может сказать, что числа "замкнуты на сложение", то есть их тип никогда не изменится, независимо от того, какие числа будут добавлены. Это означает, что мы можем выполнять цепочку операций, поскольку результатом всегда будет другое число: ```js -// we can run this on any amount of numbers +// мы можем запустить это на любом количестве чисел 1 + 7 + 5 + 4 + ... ``` -In addition to that (what a calculated pun...), we have associativity which buys us the ability to group operations however we please. Incidentally, an associative, binary operation is a recipe for parallel computation because we can chunk and distribute work. +В дополнение к этому (какой каламбур...), у нас есть ассоциативность, которая дает нам возможность группировать операции по своему усмотрению. Кстати, ассоциативные, бинарные операции - это рецепт для параллельных вычислений, потому что мы можем разбивать и распределять работу. ```js -// associativity +// ассоциативность (1 + 2) + 3 = 6 1 + (2 + 3) = 6 ``` -Now, don't go confusing this with commutativity which allows us to rearrange the order. While that holds for addition, we're not particularly interested in that property at the moment - too specific for our abstraction needs. +Не путайте это с коммутативностью, которая позволяет нам менять порядок. Это свойство справедливо и для сложения, но сейчас оно нас не особенно интересует - слишком специфично для наших абстракций. -Come to think of it, what properties should be in our abstract superclass anyways? What traits are specific to addition and what ones can be generalized? Are there other abstractions amidst this hierarchy or is it all one chunk? It's this kind of thinking that our mathematical forefathers applied when conceiving the interfaces in abstract algebra. +Если подумать, какие свойства вообще должны быть в нашем абстрактном суперклассе? Какие свойства специфичны для сложения, а какие могут быть обобщены? Есть ли среди этой иерархии другие абстракции или это все один кусок? Именно такие размышления применяли наши предки-математики, когда придумывали интерфейсы в абстрактной алгебре. -As it happens, those old school abstractionists landed on the concept of a *group* when abstracting addition. A *group* has all the bells and whistles including the concept of negative numbers. Here, we're only interested in that associative binary operator so we'll choose the less specific interface *Semigroup*. A *Semigroup* is a type with a `concat` method which acts as our associative binary operator. +Так получилось, что те абстракционисты старой школы при абстрагировании сложения остановились на концепции *группы*. У *группы* есть все возможности, включая концепцию отрицательных чисел. Здесь нас интересует только ассоциативный бинарный оператор, поэтому мы выберем менее специфичный интерфейс *Semigroup*. *Semigroup* - это тип с методом `concat`, который действует как наш ассоциативный двоичный оператор. -Let's implement it for addition and call it `Sum`: +Давайте реализуем его для сложения и назовем его `Sum`: ```js const Sum = x => ({ @@ -47,20 +47,22 @@ const Sum = x => ({ }) ``` -Note we `concat` with some other `Sum` and always return a `Sum`. +Обратите внимание, что мы `concat` с некоторым другим `Sum` и всегда возвращаем `Sum`. -I've used an object factory here instead of our typical prototype ceremony, primarily because `Sum` is not *pointed* and we don't want to have to type `new`. Anyways, here it is in action: +Я использовал здесь фабрику объектов вместо нашей типичной церемонии прототипов, прежде всего потому, что `Sum` не *ориентирована* и мы не хотим вводить `new`. В любом случае, вот он в действии: ```js Sum(1).concat(Sum(3)) // Sum(4) Sum(4).concat(Sum(37)) // Sum(41) ``` -Just like that, we can program to an interface, not an implementation. Since this interface comes from group theory it has centuries of literature backing it up. Free docs! +Вот так мы можем программировать на интерфейс, а не на реализацию. Поскольку этот интерфейс пришел из теории групп, он имеет многовековую литературу, поддерживающую его. Бесплатные документы! -Now, as mentioned, `Sum` is not *pointed*, nor a *functor*. As an exercise, go back and check the laws to see why. Okay, I'll just tell you: it can only hold a number, so `map` does not make sense here as we cannot transform the underlying value to another type. That would be a very limited `map` indeed! +Теперь, как уже упоминалось, `Sum` не является ни *ориентированным*, ни *функтором*. В качестве упражнения, вернитесь назад и проверьте законы, чтобы понять, почему. Хорошо, я просто скажу вам: она может хранить только число, поэтому `map` здесь не имеет смысла, так как мы не можем преобразовать базовое значение к другому типу. Это была бы очень ограниченная `map`! -So why is this useful? Well, as with any interface, we can swap out our instance to achieve different results: +Так почему же это полезно? Как и в случае с любым интерфейсом, мы можем менять местами наши экземпляры для достижения различных результатов: + +Переведено с помощью www.DeepL.com/Translator (бесплатная версия) ```js const Product = x => ({ x, concat: other => Product(x * other.x) }) @@ -70,7 +72,7 @@ const Min = x => ({ x, concat: other => Min(x < other.x ? x : other.x) }) const Max = x => ({ x, concat: other => Max(x > other.x ? x : other.x) }) ``` -This isn't limited to numbers, though. Let's see some other types: +Однако это не ограничивается числами. Давайте посмотрим на другие типы: ```js const Any = x => ({ x, concat: other => Any(x || other.x) }) @@ -89,14 +91,14 @@ All(true).concat(All(true)) // All(true) Map({day: 'night'}).concat(Map({white: 'nikes'})) // Map({day: 'night', white: 'nikes'}) ``` -If you stare at these long enough the pattern will pop out at you like a magic eye poster. It's everywhere. We're merging data structures, combining logic, building strings...it seems one can bludgeon almost any task into this combination based interface. +Если долго смотреть на них, узор выскочит на вас, как волшебный плакат. Она повсюду. Мы объединяем структуры данных, комбинируем логику, строим строки... кажется, что почти любую задачу можно впихнуть в этот интерфейс, основанный на комбинациях. -I've used `Map` a few times now. Pardon me if you two weren't properly introduced. `Map` simply wraps `Object` so we can embellish it with some extra methods without altering the fabric of the universe. +Я уже несколько раз использовал `Map`. Прошу прощения, если вы не были должным образом представлены. `Map` просто оборачивает `Object`, чтобы мы могли приукрасить его некоторыми дополнительными методами, не изменяя ткань вселенной. -## All my favourite functors are semigroups. +## Все мои любимые функторы являются полугруппами -The types we've seen so far which implement the functor interface all implement semigroup one as well. Let's look at `Identity` (the artist previously known as Container): +Все типы, которые мы уже видели, реализующие интерфейс функтора, также реализуют интерфейс полугруппы. Давайте рассмотрим `Identity` (исполнитель, ранее известный как Container): ```js Identity.prototype.concat = function(other) { @@ -107,21 +109,21 @@ Identity.of(Sum(4)).concat(Identity.of(Sum(1))) // Identity(Sum(5)) Identity.of(4).concat(Identity.of(1)) // TypeError: this.__value.concat is not a function ``` -It is a *semigroup* if and only if its `__value` is a *semigroup*. Like a butterfingered hang glider, it is one whilst it holds one. +Она является *полугруппой* тогда и только тогда, когда ее `__значение` является *полугруппой*. Подобно дельтаплану с масляными пальцами, он является таковым, пока удерживает его. -Other types have similar behavior: +Другие типы имеют аналогичное поведение: ```js -// combine with error handling +// сочетание с обработкой ошибок Right(Sum(2)).concat(Right(Sum(3))) // Right(Sum(5)) Right(Sum(2)).concat(Left('some error')) // Left('some error') -// combine async +// комбинирование с асинхронностью Task.of([1,2]).concat(Task.of([3,4])) // Task([1,2,3,4]) ``` -This gets particularly useful when we stack these semigroups into a cascading combination: +Это становится особенно полезным, когда мы складываем эти полугруппы в каскадную комбинацию: ```js // formValues :: Selector -> IO (Map String String) @@ -136,11 +138,11 @@ serverA.get('/friends').concat(serverB.get('/friends')) // Task([friend1, friend loadSetting('email').concat(loadSetting('general')) // Task(Maybe(Map({backgroundColor: true, autoSave: false}))) ``` -In the top example, we've combined an `IO` holding an `Either` holding a `Map` to validate and merge form values. Next, we've hit a couple of different servers and combined their results in an async way using `Task` and `Array`. Lastly, we've stacked `Task`, `Maybe`, and `Map` to load, parse, and merge multiple settings. +В верхнем примере мы объединили `IO` с `Either` и `Map` для проверки и объединения значений формы. Далее мы обратились к нескольким различным серверам и объединили их результаты асинхронным способом, используя `Task` и `Array`. Наконец, мы объединили `Task`, `Maybe` и `Map` для загрузки, разбора и объединения нескольких параметров. -These can be `chain`ed or `ap`'d, but *semigroups* capture what we'd like to do much more concisely. +Это могут быть `цепочки` или `ap`, но *полугруппы* передают то, что мы хотели бы сделать гораздо более лаконично. -This extends beyond functors. In fact, it turns out that anything made up entirely of semigroups, is itself, a semigroup: if we can concat the kit, then we can concat the caboodle. +Это выходит за рамки функторов. На самом деле, оказывается, что все, что полностью состоит из полугрупп, само является полугруппой: если мы можем объединить набор, то мы можем объединить и все остальное. ```js const Analytics = (clicks, path, idleTime) => ({ @@ -155,16 +157,16 @@ Analytics(Sum(2), ['/home', '/about'], Right(Max(2000))).concat(Analytics(Sum(1) // Analytics(Sum(3), ['/home', '/about', '/contact'], Right(Max(2000))) ``` -See, everything knows how to combine itself nicely. Turns out, we could do the same thing for free just by using the `Map` type: +Видите, все знает, как красиво объединить себя. Оказывается, мы можем сделать то же самое бесплатно, просто используя тип `Map`: ```js Map({clicks: Sum(2), path: ['/home', '/about'], idleTime: Right(Max(2000))}).concat(Map({clicks: Sum(1), path: ['/contact'], idleTime: Right(Max(1000))})) // Map({clicks: Sum(3), path: ['/home', '/about', '/contact'], idleTime: Right(Max(2000))}) ``` -We can stack and combine as many of these as we'd like. It's simply a matter of adding another tree to the forest, or another flame to the forest fire depending on your codebase. +Мы можем складывать и комбинировать их столько, сколько захотим. Это просто вопрос добавления еще одного дерева в лес или еще одного пламени в лесной пожар, в зависимости от вашей кодовой базы. -The default, intuitive behavior is to combine what a type is holding, however, there are cases where we ignore what's inside and combine the containers themselves. Consider a type like `Stream`: +Интуитивно понятное поведение по умолчанию - объединять то, что содержит тип, однако есть случаи, когда мы игнорируем то, что находится внутри, и объединяем сами контейнеры. Рассмотрим такой тип, как `Stream`: ```js const submitStream = Stream.fromEvent('click', $('#submit')) @@ -173,21 +175,21 @@ const enterStream = filter(x => x.key === 'Enter', Stream.fromEvent('keydown', $ submitStream.concat(enterStream).map(submitForm) // Stream() ``` -We can combine event streams by capturing events from both as one new stream. Alternatively, we could have combined them by insisting they hold a semigroup. In fact, there are many possible instances for each type. Consider `Task`, we can combine them by choosing the earlier or later of the two. We can always chose the first `Right` instead of short circuiting on `Left` which has the effect of ignoring errors. There is an interface called *Alternative* which implements some of these, well, alternative instances, typically focused on choice rather than cascading combination. It is worth looking into if you are in need of such functionality. +Мы можем объединить потоки событий, фиксируя события из обоих потоков как один новый поток. В качестве альтернативы мы могли бы объединить их, настаивая на том, что они содержат полугруппу. На самом деле, существует множество возможных экземпляров для каждого типа. Рассмотрим `Task`, мы можем объединить их, выбрав более ранний или более поздний из двух. Мы всегда можем выбрать первое `Право` вместо замыкания на `Лево`, что имеет эффект игнорирования ошибок. Существует интерфейс под названием *Alternative*, который реализует некоторые из этих, ну, альтернативных экземпляров, обычно ориентированных на выбор, а не на каскадное комбинирование. На него стоит обратить внимание, если вам нужна такая функциональность. -## Monoids for nothing +## Моноиды просто так -We were abstracting addition, but like the Babylonians, we lacked the concept of zero (there were zero mentions of it). +Мы абстрагировали сложение, но, подобно вавилонянам, нам не хватало понятия нуля (было ноль упоминаний о нем). -Zero acts as *identity* meaning any element added to `0`, will return back that very same element. Abstraction-wise, it's helpful to think of `0` as a kind of neutral or *empty* element. It's important that it act the same way on the left and right side of our binary operation: +Ноль действует как *идентичность*, то есть любой элемент, добавленный к `0`, вернет обратно тот же самый элемент. С точки зрения абстракции, полезно думать о `0` как о некоем нейтральном или *пустом* элементе. Важно, чтобы он действовал одинаково с левой и правой стороны нашей бинарной операции: ```js -// identity +// идентичность 1 + 0 = 1 0 + 1 = 1 ``` -Let's call this concept `empty` and create a new interface with it. Like so many startups, we'll choose a heinously uninformative, yet conveniently googleable name: *Monoid*. The recipe for *Monoid* is to take any *semigroup* and add a special *identity* element. We'll implement that with an `empty` function on the type itself: +Назовем эту концепцию `empty` и создадим с ее помощью новый интерфейс. Как и многие другие стартапы, мы выберем чудовищно неинформативное, но удобное для гугла название: *Monoid*. Рецепт *Monoid* заключается в том, чтобы взять любую *полугруппу* и добавить специальный элемент *идентичности*. Мы реализуем это с помощью функции `empty` для самого типа: ```js Array.empty = () => [] @@ -200,11 +202,11 @@ All.empty = () => All(true) Any.empty = () => Any(false) ``` -When might an empty, identity value prove useful? That's like asking why zero is useful. Like not asking anything at all... +Когда пустая, тождественная величина может оказаться полезной? Это все равно, что спросить, почему ноль полезен. Как и вообще ничего не спрашивать... -When we have nothing else, who can we count on? Zero. How many bugs do we want? Zero. It's our tolerance for unsafe code. A fresh start. The ultimate price tag. It can annihilate everything in its path or save us in a pinch. A golden life saver and a pit of despair. +Когда у нас больше ничего нет, на кого мы можем рассчитывать? На ноль. Сколько жучков нам нужно? Ноль. Это наша терпимость к небезопасному коду. Свежий старт. Конечная цена. Он может уничтожить все на своем пути или спасти нас в трудную минуту. Золотой спасательный круг и яма отчаяния. -Codewise, they correspond to sensible defaults: +В кодовом отношении они соответствуют разумным значениям по умолчанию: ```js const settings = (prefix="", overrides=[], total=0) => ... @@ -212,17 +214,17 @@ const settings = (prefix="", overrides=[], total=0) => ... const settings = (prefix=String.empty(), overrides=Array.empty(), total=Sum.empty()) => ... ``` -Or to return a useful value when we have nothing else: +Или чтобы вернуть полезное значение, когда у нас больше ничего нет: ```js sum([]) // 0 ``` -They are also the perfect initial value for an accumulator... +Они также являются идеальным начальным значением для аккумулятора... -## Folding down the house +## Собираем всё вместе -It just so happens that `concat` and `empty` fit perfectly in the first two slots of `reduce`. We can actually `reduce` an array of *semigroup*'s down by ignoring the *empty* value, but as you can see, that leads to a precarious situation: +Так получилось, что `concat` и `empty` идеально вписываются в первые два слота `reduce`. На самом деле мы можем `reduce` массив *semigroup*, игнорируя значение *empty*, но, как вы видите, это приводит к опасной ситуации: ```js // concat :: Semigroup s => s -> s -> s @@ -233,16 +235,16 @@ const concat = x => y => x.concat(y) [].reduce(concat) // TypeError: Reduce of empty array with no initial value ``` -Boom goes the dynamite. Like a twisted ankle in a marathon, we have ourselves a runtime exception. JavaScript is more than happy to let us strap pistols to our sneakers before running - it is a conservative sort of language, I suppose, but it stops us dead in our tracks when the array is barren. What could it return anyhow? `NaN`, `false`, `-1`? If we were to continue on in our program, we'd like a result of the right type. It could return a `Maybe` to indicate the possibility of failure, but we can do one better. +Бум динамита. Как вывихнутая лодыжка в марафоне, мы получили исключение времени выполнения. JavaScript более чем счастлив позволить нам пристегнуть пистолеты к кроссовкам перед бегом - это консервативный язык, я полагаю, но он останавливает нас на месте, когда массив оказывается бесплодным. Что же он может вернуть? `NaN`, `false`, `-1`? Если бы мы продолжили работу в нашей программе, мы бы хотели получить результат нужного типа. Он мог бы вернуть `Maybe`, чтобы указать на возможность неудачи, но мы можем сделать кое-что получше. -Let's use our curried `reduce` function and make a safe version where the `empty` value is not optional. It shall henceforth be known as `fold`: +Давайте воспользуемся нашей каррированной функцией `reduce` и сделаем безопасную версию, в которой значение `empty` не является необязательным. Отныне она будет называться `fold`: ```js // fold :: Monoid m => m -> [m] -> m const fold = reduce(concat) ``` -The initial `m` is our `empty` value - our neutral, starting point, then we take an array of `m`'s and crush them down to one beautiful diamond like value. +Начальное `m` - это наше `пустое` значение - наша нейтральная, отправная точка, затем мы берем массив `m` и дробим их до одного красивого значения, похожего на бриллиант. ```js fold(Sum.empty(), [Sum(1), Sum(2)]) // Sum(3) @@ -258,11 +260,11 @@ fold(Either.of(Max.empty()), [Right(Max(3)), Left('error retrieving value'), Rig fold(IO.of([]), ['.link', 'a'].map($)) // IO([,