Skip to content

Commit

Permalink
Update from original english version (#84)
Browse files Browse the repository at this point in the history
  • Loading branch information
vladimirlogachev authored Jun 2, 2020
1 parent e78432f commit e111269
Show file tree
Hide file tree
Showing 22 changed files with 711 additions and 28 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ less
Gruntfile.js
npm-debug.log
.DS_Store
.vscode
*.md#*
_book
/book.pdf
Expand Down
2 changes: 1 addition & 1 deletion README-en.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ For a best reading experience, [read it online via Gitbook](https://mostly-adequ

## Play Around with Code

To make the training efficient and not get too bored while I am telling you another story, make sure to play around with the concepts introduced in this book. Some can be tricky to catch at first and are better understood by getting your hand dirty.
To make the training efficient and not get too bored while I am telling you another story, make sure to play around with the concepts introduced in this book. Some can be tricky to catch at first and are better understood by getting your hands dirty.
All functions and algebraic data-structures presented in the book are gathered in the appendixes. The corresponding code is also available as an npm module:

```bash
Expand Down
11 changes: 11 additions & 0 deletions SUMMARY-ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,16 @@
* [Законы и архитектурный беспорядок](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)
Expand All @@ -106,6 +116,7 @@
* [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)
Expand Down
11 changes: 11 additions & 0 deletions SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@
* [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)
Expand All @@ -108,6 +118,7 @@
* [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)
Expand Down
2 changes: 1 addition & 1 deletion appendix_a-ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const always = curry((a, b) => a);
## compose

```js
// compose :: ((a -> b), (b -> c), ..., (y -> z)) -> a -> z
// compose :: ((y -> z), (x -> y), ..., (a -> b)) -> a -> z
const compose = (...fns) => (...args) => fns.reduceRight((res, fn) => [fn.call(null, ...res)], args)[0];
```

Expand Down
2 changes: 1 addition & 1 deletion appendix_a.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const always = curry((a, b) => a);
## compose

```js
// compose :: ((a -> b), (b -> c), ..., (y -> z)) -> a -> z
// compose :: ((y -> z), (x -> y), ..., (a -> b)) -> a -> z
const compose = (...fns) => (...args) => fns.reduceRight((res, fn) => [fn.call(null, ...res)], args)[0];
```

Expand Down
2 changes: 1 addition & 1 deletion ch03.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const checkAge = (age) => {

In the impure portion, `checkAge` depends on the mutable variable `minimum` to determine the result. In other words, it depends on system state which is disappointing because it increases the [cognitive load](https://en.wikipedia.org/wiki/Cognitive_load) by introducing an external environment.

It might not seem like a lot in this example, but this reliance upon state is one of the largest contributors to system complexity (http://curtclifton.net/papers/MoseleyMarks06a.pdf). This `checkAge` may return different results depending on factors external to input, which not only disqualifies it from being pure, but also puts our minds through the ringer each time we're reasoning about the software.
It might not seem like a lot in this example, but this reliance upon state is one of the largest contributors to system complexity (http://curtclifton.net/papers/MoseleyMarks06a.pdf). This `checkAge` may return different results depending on factors external to input, which not only disqualifies it from being pure, but also puts our minds through the wringer each time we're reasoning about the software.

Its pure form, on the other hand, is completely self sufficient. We can also make `minimum` immutable, which preserves the purity as the state will never change. To do this, we must create an object to freeze.

Expand Down
2 changes: 1 addition & 1 deletion ch04-ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ const allTheChildren = elements => map(elements, getChildren);

#### Упражнение A

Проведите рефакторинг и избавьтесь от аргумента путём частичного применения функции.
Проведите рефакторинг и избавьтесь от аргументов, используя частичное применение функции.

```js
const words = str => split(' ', str);
Expand Down
2 changes: 1 addition & 1 deletion ch04.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ answers to the exercises are available in files named *answers\_\**.
#### Let's Practice!

{% exercise %}
Refactor to remove the argument by partially applying the function.
Refactor to remove all arguments by partially applying the function.

{% initial src="./exercises/ch04/exercise_a.js#L3;" %}
```js
Expand Down
2 changes: 1 addition & 1 deletion ch05-ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ const averageDollarValue = (cars) => {

### Упражнение C

Проведите рефакторинг, приведите `fastestCar` к бесточечному стилю, используя `compose()` и другие функции. Подсказка: вам может пригодиться функция `flip`.
Проведите рефакторинг, приведите `fastestCar` к бесточечному стилю, используя `compose()` и другие функции. Подсказка: вам может пригодиться функция `append`.

```js
const fastestCar = (cars) => {
Expand Down
4 changes: 2 additions & 2 deletions ch05.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Instead of inside to outside, we run right to left, which I suppose is a step in

```js
const head = x => x[0];
const reverse = reduce((acc, x) => [x].concat(acc), []);
const reverse = reduce((acc, x) => [x, ...acc], []);
const last = compose(head, reverse);

last(['jumpkick', 'roundhouse', 'uppercut']); // 'uppercut'
Expand Down Expand Up @@ -330,7 +330,7 @@ const averageDollarValue = (cars) => {

{% exercise %}
Refactor `fastestCar` using `compose()` and other functions in pointfree-style. Hint, the
`flip` function may come in handy.
`append` function may come in handy.

{% initial src="./exercises/ch05/exercise_c.js#L4;" %}
```js
Expand Down
2 changes: 1 addition & 1 deletion ch07.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ You don't need any code to get these theorems, they follow directly from the typ

You might think, well that's just common sense. But last I checked, computers don't have common sense. Indeed, they must have a formal way to automate these kind of code optimizations. Maths has a way of formalizing the intuitive, which is helpful amidst the rigid terrain of computer logic.

The `filter` theorem is similar. It says that if we compose `f` and `p` to check which should be filtered, then actually apply the `f` via `map` (remember filter, will not transform the elements - its signature enforces that `a` will not be touched), it will always be equivalent to mapping our `f` then filtering the result with the `p` predicate.
The `filter` theorem is similar. It says that if we compose `f` and `p` to check which should be filtered, then actually apply the `f` via `map` (remember `filter` will not transform the elements - its signature enforces that `a` will not be touched), it will always be equivalent to mapping our `f` then filtering the result with the `p` predicate.

These are just two examples, but you can apply this reasoning to any polymorphic type signature and it will always hold. In JavaScript, there are some tools available to declare rewrite rules. One might also do this via the `compose` function itself. The fruit is low hanging and the possibilities are endless.

Expand Down
3 changes: 1 addition & 2 deletions ch08-ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ getAge(moment(), { birthDate: 'July 4, 2001' });

```js
// fortune :: Number -> String
const fortune = compose(append('If you survive, you will be '), toString, add(1));
const fortune = compose(concat('If you survive, you will be '), toString, add(1));

// zoltar :: User -> Either(String, _)
const zoltar = compose(map(console.log), map(fortune), getAge(moment()));
Expand Down Expand Up @@ -462,7 +462,6 @@ const findParam = key => map(compose(Maybe.of, find(compose(eq(key), head)), par
findParam('searchTerm').$value();
// Just(['searchTerm', 'wafflehouse'])
```
<!-- Исправлена сигнатура и имплементация findParam https://github.com/MostlyAdequate/mostly-adequate-guide/pull/538 -->

Вот так мы отмазались от запуска «эффектных» вычислений, возвращая `url` завёрнутым в `IO` _(это является хорошим тоном при написании кода библиотек)_. Как вы могли заметить, мы легко можем содержать один контейнер в другом. В этом примере очень удобно оперировать `IO(Maybe([x]))` – он представляет из себя 3 функтора, вложенных один в другой _(`IO`, `Maybe` и `Array`, при этом нам вряд ли понадобится применять `map` к массиву, ведь он используется здесь для хранения **пары** значений, а не для того, чтобы выразить недетерминированность результата – прим. пер.)_, что обосновано и весьма выразительно.

Expand Down
12 changes: 6 additions & 6 deletions ch08.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ Now, just like `Nothing`, we are short-circuiting our app when we return a `Left

```js
// fortune :: Number -> String
const fortune = compose(append('If you survive, you will be '), toString, add(1));
const fortune = compose(concat('If you survive, you will be '), toString, add(1));

// zoltar :: User -> Either(String, _)
const zoltar = compose(map(console.log), map(fortune), getAge(moment()));
Expand Down Expand Up @@ -455,14 +455,14 @@ const toPairs = compose(map(split('=')), split('&'));
// params :: String -> [[String]]
const params = compose(toPairs, last, split('?'));

// findParam :: String -> IO Maybe [[String]]
const findParam = key => map(compose(Maybe.of, filter(compose(eq(key), head)), params), url);
// findParam :: String -> IO Maybe [String]
const findParam = key => map(compose(Maybe.of, find(compose(eq(key), head)), params), url);

// -- Impure calling code ----------------------------------------------

// run it by calling $value()!
findParam('searchTerm').$value();
// Just([['searchTerm', 'wafflehouse']])
// Just(['searchTerm', 'wafflehouse'])
```

Our library keeps its hands clean by wrapping `url` in an `IO` and passing the buck to the caller. You might have also noticed that we have stacked our containers; it's perfectly reasonable to have a `IO(Maybe([x]))`, which is three functors deep (`Array` is most definitely a mappable container type) and exceptionally expressive.
Expand Down Expand Up @@ -628,8 +628,8 @@ You see, they are equal. Next let's look at composition.
const compLaw1 = compose(map(append(' world')), map(append(' cruel')));
const compLaw2 = map(compose(append(' world'), append(' cruel')));

compLaw1(Container.of('Goodbye')); // Container(' world cruelGoodbye')
compLaw2(Container.of('Goodbye')); // Container(' world cruelGoodbye')
compLaw1(Container.of('Goodbye')); // Container('Goodbye cruel world')
compLaw2(Container.of('Goodbye')); // Container('Goodbye cruel world')
```

In category theory, functors take the objects and morphisms of a category and map them to a different category. By definition, this new category must have an identity and the ability to compose morphisms, but we needn't check because the aforementioned laws ensure these are preserved.
Expand Down
2 changes: 1 addition & 1 deletion ch11.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ We are about to discuss *natural transformations* in the context of practical ut

## Curse This Nest

I'd like to address the issue of nesting. Not the instinctive urge felt by soon to be mothers wherein they tidy and rearrange with obsessive compulsion, but the...well actually, come to think of it, that isn't far from the mark as we'll see in the coming chapters... In any case, what I mean by *nesting* is to have two or more different types all huddled together around a value, cradling it like a newborn, as it were.
I'd like to address the issue of nesting. Not the instinctive urge felt by soon to be parents wherein they tidy and rearrange with obsessive compulsion, but the...well actually, come to think of it, that isn't far from the mark as we'll see in the coming chapters... In any case, what I mean by *nesting* is to have two or more different types all huddled together around a value, cradling it like a newborn, as it were.

```js
Right(Maybe('b'));
Expand Down
6 changes: 3 additions & 3 deletions ch12-ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// readFile :: FileName -> Task Error String

// firstWords :: String -> String
const firstWords = compose(join(' '), take(3), split(' '));
const firstWords = compose(intercalate(' '), take(3), split(' '));

// tldr :: FileName -> Task Error String
const tldr = compose(map(firstWords), readFile);
Expand Down Expand Up @@ -151,7 +151,7 @@ traverse(of, fn) {
// readFile :: FileName -> Task Error String

// firstWords :: String -> String
const firstWords = compose(join(' '), take(3), split(' '));
const firstWords = compose(intercalate(' '), take(3), split(' '));

// tldr :: FileName -> Task Error String
const tldr = compose(map(firstWords), readFile);
Expand Down Expand Up @@ -248,7 +248,7 @@ traverse(A.of, A.of) === A.of;

## Итог

*Traversable* — это мощный интерфейс, который даёт нам возможность реорганизовывать типы так же легко, как если бы мы могли мыслями двигать мебель и менять интерьер. Мы можем получать различные эффекты в разном порядке, а также разглаживать неприятные «морщины» из типов, которые препятствуют применению `join`. В следующей главе мы изучим один из самых мощных интерфейсов в функциональном программировании, а может быть и во всей алгебре: [Глава 13: Monoids bring it all together](ch13-ru.md) _(ещё не опубликована в оригинальной книге)_.
*Traversable* — это мощный интерфейс, который даёт нам возможность реорганизовывать типы так же легко, как если бы мы могли мыслями двигать мебель и менять интерьер. Мы можем получать различные эффекты в разном порядке, а также разглаживать неприятные «морщины» из типов, которые препятствуют применению `join`. В следующей главе мы изучим один из самых мощных интерфейсов в функциональном программировании, а может быть и во всей алгебре: [Глава 13: Monoids bring it all together](ch13-ru.md).

## Упражнения

Expand Down
4 changes: 2 additions & 2 deletions ch12.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Let's get weird:
// readFile :: FileName -> Task Error String

// firstWords :: String -> String
const firstWords = compose(join(' '), take(3), split(' '));
const firstWords = compose(intercalate(' '), take(3), split(' '));

// tldr :: FileName -> Task Error String
const tldr = compose(map(firstWords), readFile);
Expand Down Expand Up @@ -149,7 +149,7 @@ Time to revisit and clean our initial examples.
// readFile :: FileName -> Task Error String

// firstWords :: String -> String
const firstWords = compose(join(' '), take(3), split(' '));
const firstWords = compose(intercalate(' '), take(3), split(' '));

// tldr :: FileName -> Task Error String
const tldr = compose(map(firstWords), readFile);
Expand Down
Loading

0 comments on commit e111269

Please sign in to comment.