{"action":"created","comment":{"url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/pulls/comments/39276899","id":39276899,"diff_hunk":"@@ -0,0 +1,445 @@\n+# Chapter 3: Pure Happiness with Pure Functions\n+# Глава 3: Чистое счастье с Чистыми функциями\n+\n+## Oh to be pure again\n+## Как же хорошо снова быть чистым\n+\n+One thing we need to get straight is the idea of a pure function.\n+\n+Нам совершенно необходимо чётко понять концепцию чистой функции.\n+\n+>A pure function is a function that, given the same input, will always return the same output and does not have any observable side effect.\n+\n+>Чистая функция — это функция, которая при одинаковых аргументах всегда возращает одни и то же значения и не имеет видимых побочных эффектов.\n+\n+Take `slice` and `splice`. They are two functions that do the exact same thing - in a vastly different way, mind you, but the same thing nonetheless. We say `slice` is *pure* because it returns the same output per input every time, guaranteed. `splice`, however, will chew up its array and spit it back out forever changed which is an observable effect.\n+\n+Для примера рассмотрим `slice` и `splice`. Эти две функции работают абсолютно одинаково, хотя и делают это совершенно по-разному. Функция `slice` является *чистой*, потому что для одинаковых входных значений она всегда возвращает одни и те же значения на выходе. `splice`, с другой стороны, «съест» кусок массива и вернёт изменённую переменную, что и является побочным эффектом.\n+\n+```js\n+var xs = [1,2,3,4,5];\n+\n+// чистая\n+xs.slice(0,3);\n+//=> [1,2,3]\n+\n+xs.slice(0,3);\n+//=> [1,2,3]\n+\n+xs.slice(0,3);\n+//=> [1,2,3]\n+\n+\n+// не чистая\n+xs.splice(0,3);\n+//=> [1,2,3]\n+\n+xs.splice(0,3);\n+//=> [4,5]\n+\n+xs.splice(0,3);\n+//=> []\n+```\n+\n+In functional programming, we dislike unwieldy functions like `splice` that *mutate* data. This will never do as we're striving for reliable functions that return the same result every time, not functions that leave a mess in their wake like `splice`.\n+\n+В функциональном программировании мы не любим неуклюжие функции, такие как `splice`, которые изменяют данные. Такое поведение совершенно неприемлемо, потому как мы стремимся к написанию надёжных функций. Таких, которые для одинаковых входных данных возвращают одни и те же выходные. Нам не интересны функции, оставляющие за собой беспорядок в виде испорченных данных, как `splice`.\n+\n+Let's look at another example.\n+\n+Приведу ещё один пример.\n+\n+```js\n+// не чистая\n+var minimum = 21;\n+\n+var checkAge = function(age) {\n+  return age >= minimum;\n+};\n+\n+\n+\n+// чистая\n+var checkAge = function(age) {\n+  var minimum = 21;\n+  return age >= minimum;\n+};\n+```\n+\n+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 by introducing an external environment.\n+\n+В не чистом примере, `checkAge` использует изменяемую переменную `minimum`, другими словами, она зависит от состояния системы, что плохо, так как это усложняет понимание функции из-за связанности с внешней средой.\n+\n+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://www.curtclifton.net/storage/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.\n+\n+В данном примере это может показаться мелочью, но зависимость системы от своего состояния — это один из самых важных факторов её сложности[^http://www.curtclifton.net/storage/papers/MoseleyMarks06a.pdf]. Функция `checkAge` может возвращать разные значения, в зависимости от вншнего фактора, что не только исключает её из класса чистых, но ещё и затрудняет её понимание, каждый раз когда мы пытаемся проанализировать код.\n+\n+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.\n+\n+Её чистый вариант, наоборот, полностью самодостаточен. Мы также можем сделать переменную `minimum` неизменяемой, что позволит сохранить чистоту, так как состояние никогда не изменится. Чтобы добиться этого нам потребуется использовать метод `freeze` класса `Object`.\n+\n+```js\n+var immutableState = Object.freeze({\n+  minimum: 21\n+});\n+```\n+\n+## Side effects may include...\n+## Среди побочных эффектов может наблюдаться...\n+\n+Let's look more at these \"side effects\" to improve our intuition. So what is this undoubtedly nefarious *side effect* mentioned in the definition of *pure function*? We'll be referring to *effect* as anything that occurs in our computation besides the calculation of a result.\n+\n+Давайте более подробно разберёмся с этими «побочными эффектами», дабы развить нашу интуицию. Что же за именно скрывается за этими несомненно гнусными *побочными эффектами*, упомянутыми в определении *чистой функции*? Мы будем считать *эффектом* всё, что вызывает какое-либо вычисление, кроме результата самой функции.\n+\n+There's nothing intrinsically bad about effects and we'll be using them all over the place in the chapters to come. It's that *side* part that bears the negative connotation. Water alone is not an inherent larvae incubator, it's the *stagnant* part that yields the swarms, and I assure you, *side* effects are a similar breeding ground in your own programs.\n+\n+В эффектах нет ничего «врождённо» плохого, напротив, в будущих главах мы будем использовать их постоянно. Негативную окраску добавляет именно прилагательное «побочный». В слове «вода» нет негативных оттенков, *застоявшаяся* вода — напротив, вызывает ассоциации бактерий и тухлятины. То же самое и с *побочными* эффектами в ваших программах.\n+\n+>A *side effect* is a change of system state or *observable interaction* with the outside world that occurs during the calculation of a result.\n+\n+>*Побочный эффект* — это изменение состояния системы или *заметное взаимодействие* с окружающим миром, которое происходит во время вычисления результата.\n+\n+Side effects may include, but are not limited to\n+Побочные эффекты могут включать (но не ограничиваются):\n+\n+  * changing the file system\n+  * inserting a record into a database\n+  * making an http call\n+  * mutations\n+  * printing to the screen / logging\n+  * obtaining user input\n+  * querying the DOM\n+  * accessing system state\n+  \n+  \n+  * изменениями в файловой системе\n+  * вставкой записи в базу данных\n+  * выполнение http-запроса\n+  * мутациями\n+  * выводом на экран / записью в лог\n+  * получением данных от пользователя\n+  * выполнением запроса к DOM\n+  * получением доступа к состоянию системы\n+  \n+\n+And the list goes on and on. Any interaction with the world outside of a function is a side effect, which is a fact that may prompt you to suspect the practicality of programming without them. The philosophy of functional programming postulates that side effects are a primary cause of incorrect behavior.\n+\n+Это далеко не полный список. Любое взаимодействие с миром вне функции уже является побочным эффектом, что может вызвать в вас сомнения в пользе отказа от побочных эффектов в программировании. Философия функционального программирования постулирует, что побочные эффекты являются первопричиной некорректного поведения.\n+\n+It is not that we're forbidden to use them, rather we want to contain them and run them in a controlled way. We'll learn how to do this when we get to functors and monads in later chapters, but for now, let's try to keep these insidious functions separate from our pure ones.\n+\n+Мы не собираемся полностью отказываться от них, лучше ... Мы научимся делать это используя функторы и монады в последующих главах, сейчас же, мы просто будем отделять коварные функции вызывающие побочные эффекты от чистых.\n+\n+Side effects disqualify a function from being *pure* and it makes sense: pure functions, by definition, must always return the same output given the same input, which is not possible to guarantee when dealing with matters outside our local function.\n+\n+Побочные эффекты исключают функцию из лиги *чистых* и это имеет свой смысл: чистые функции, по определению, обязаны всегда возвращать одно и то же значение, для одинаковых входных данных, что невозможно обеспечить, когда имеешь дело с зависимостями вне самой функции.\n+\n+Let's take a closer look at why we insist on the same output per input. Pop your collars, we're going to look at some 8th grade math.\n+\n+Давайте разберёмся, почему я так наставиваю на одном и том же результате при одинаковых входных данных. Садитесь за парту ровно, я покажу вам немного математики из 8го класса.\n+\n+## Математика 8го класса\n+\n+From mathisfun.com:\n+\n+С сайта mathisfun.com\n+\n+> A function is a special relationship between values:\n+> Each of its input values gives back exactly one output value.\n+\n+> Фунцкия — это взаимоотношение между величинами:\n+> Каждое из входных значений возвращает одно и только одно выходное.\n+\n+In other words, it's just a relation between two values: the input and the output. Though each input has exactly one output, that output doesn't necessarily have to be unique per input. Below shows a diagram of a perfectly valid function from `x` to `y`;\n+\n+Другими словами, функция — это всего лишь взаимоотношение между двумя величинами: аргументом и значением. Хотя и каждому аргументу ставится в соответствие единственное значение функции, обратное не верно. Так, функция, вызванная с разными аргументами может возвращать одно и то же значение. На диаграмме ниже изображена вполне законная функция `x` → `y`.\n+\n+<img src=\"images/function-sets.gif\" />[^http://www.mathsisfun.com/sets/function.html]\n+\n+To contrast, the following diagram shows a relation that is *not* a function since the input value `5` points to several outputs:\n+\n+Для сравнения, следующая диаграмма показывает отношение, которое *не* является функцией. Так как для аргумента `5` есть несколько значений:\n+\n+<img src=\"images/relation-not-function.gif\" />[^http://www.mathsisfun.com/sets/function.html]\n+\n+Functions can be described as a set of pairs with the position (input, output): `[(1,2), (3,6), (5,10)]`[^It appears this function doubles its input].\n+\n+Функцию можно описать как набор упорядоченных пар (аргумент, значение): `[(1,2), (3,6), (5,10)]`[^Похоже, что эта функция удваивает аргумент].\n+\n+Or perhaps a table:\n+\n+Или в виде таблицы:\n+<table> <tr> <th>Input</th> <th>Output</th> </tr> <tr> <td>1</td> <td>2</td> </tr> <tr> <td>2</td> <td>4</td> </tr> <tr> <td>3</td> <td>6</td> </tr> </table>\n+\n+<table> <tr> <th>Аргумент</th> <th>Значение</th> </tr> <tr> <td>1</td> <td>2</td> </tr> <tr> <td>2</td> <td>4</td> </tr> <tr> <td>3</td> <td>6</td> </tr> </table>\n+\n+Or even as a graph with `x` as the input and `y` as the output:\n+\n+Или в виде графика, где по оси `x` отложен аргумент, а по оси `y` — значение:\n+\n+<img src=\"images/fn_graph.png\" width=\"300\" height=\"300\" />\n+\n+\n+There's no need for implementation details if the input dictates the output. Since functions are simply mappings of input to output, one could simply jot down object literals and run them with `[]` instead of `()`.\n+\n+Нам совершенно не важны детали реализации механизма функции, если мы знаем, что аргумент диктует значение. Так как функции являются всего лишь отображением аргумента на значение, то мы можем просто-напросто записывать литералы объекта с `[]`, вместо `()`.\n+\n+```js\n+var toLowerCase = {\"A\":\"a\", \"B\": \"b\", \"C\": \"c\", \"D\": \"d\", \"E\": \"e\", \"D\": \"d\"};\n+\n+toLowerCase[\"C\"];\n+//=> \"c\"\n+\n+var isPrime = {1:false, 2: true, 3: true, 4: false, 5: true, 6:false};\n+\n+isPrime[3];\n+//=> true\n+```\n+\n+Of course, you might want to calculate instead of hand writing things out, but this illustrates a different way to think about functions.[^You may be thinking \"what about functions with multiple arguments?\". Indeed, that presents a bit of an inconvenience when thinking in terms of mathematics. For now, we can bundle them up in an array or just think of the `arguments` object as the input. When we learn about *currying*, we'll see how we can directly model the mathematical definition of a function.]\n+\n+Согласен, возможно вы захотите вычислять значение функции, а не просто вписывать вручную все возможные пар аргументов-значений.[^Кто-то из вас может заметить: «а как же функции многих переменных?» Действительно, с точки зрения может показаться несколько странным что мы не обговорили этот момент. На данный момент, будем считать несколько аргументов как один аргумент, являющийся массивом. Когда мы изучим *каррирование*, мы сможем легко пользоваться строгим математическим определением функции.]\n+\n+Here comes the dramatic reveal: Pure functions *are* mathematical functions and they're what functional programming is all about. Programming with these little angels can provide huge benefits. Let's look at some reasons why we're willing to go to great lengths to preserve purity.\n+\n+Здесь нас поджидает внезапное открытие: чистые функции *являются* математическими функциями, они явяляются фундаментом функционального программирования. Использование этих маленьких ангелочков таит в себе большое количество плюсов. Давайте посмотрим, зачем так стараться ради сохранения чистоты.\n+\n+## The case for purity\n+## Место для чистоты\n+\n+### Cacheable\n+### Кешируемость\n+\n+For starters, pure functions can always be cached by input. This is typically done using a technique called memoization:\n+\n+Начнём с того, что значения чистых функций можно кешировать по аргументу. Обычно это реализуется с помощью техники мемоизации:\n+\n+```js\n+var squareNumber  = memoize(function(x){ return x*x; });\n+\n+squareNumber(4);\n+//=> 16\n+\n+squareNumber(4); // возвращает результат из кеша для аргумента 4\n+//=> 16\n+\n+squareNumber(5);\n+//=> 25\n+\n+squareNumber(5); // возвращает результат из кеша для аргумента 5\n+//=> 25\n+```\n+\n+Here is a simplified implementation, though there are plenty of more robust versions available.\n+\n+Ниже я написал упрощённую реализацию мемоизации, в интернете вы можете найти более надёжную версию.\n+\n+```js\n+var memoize = function(f) {\n+  var cache = {};\n+\n+  return function() {\n+    var arg_str = JSON.stringify(arguments);\n+    cache[arg_str] = cache[arg_str] || f.apply(f, arguments);\n+    return cache[arg_str];\n+  };\n+};\n+```\n+\n+Something to note is that you can transform some impure functions into pure ones by delaying evaluation:\n+\n+Некоторые функции можно превратить в чистые благодаря отложенному выполнению:\n+\n+```js\n+var pureHttpCall = memoize(function(url, params){\n+  return function() { return $.getJSON(url, params); }\n+});\n+```\n+\n+The interesting thing here is that we don't actually make the http call - we instead return a function that will do so when called. This function is pure because it will always return the same output given the same input: the function that will make the particular http call given the `url` and `params`.\n+\n+Интересный момент, мы не делаем http-запрос, вместо него мы возвращаем функцию, которая сделает, когда будет вызвана. Эта функция является чистой, так как всегда для одинакового аргумента возвращает одно и то же значение — функцию, которая сделает http-запрос по заданным `url` и `params`.\n+\n+Our `memoize` function works just fine, though it doesn't cache the results of the http call, rather it caches the generated function.\n+\n+Функция `memoize` работает нормально, хотя она и не кеширует результат http-запроса, а кеширует сгенерированную функцию.\n+\n+This is not very useful yet, but we'll soon learn some tricks that will make it so. The takeaway is that we can cache every function no matter how destructive they seem.\n+\n+Пока что `memoize` не кажется очень полезной, однако скоро мы изучим некоторые хитрости, которые позволят кешировать любую функцию, вне зависимости от её чистоты.\n+\n+### Portable / Self-Documenting\n+### Переносимость / Самодокументированность\n+\n+Pure functions are completely self contained. Everything the function needs is handed to it on a silver platter. Ponder this for a moment... How might this be beneficial? For starters, a function's dependencies are explicit and therefore easier to see and understand - no funny business going on under the hood.\n+\n+Чистые функцию полностью самодостаточны, всё что им нужно для работы они получают на блюдечке. Вдумайтесь, какие в этом могут быть плюсы? Начнём с зависимостей: они явные и, следовательно, их проще отследить — ничего не скрыто под капотом.\n+\n+```js\n+// не чистая\n+var signUp = function(attrs) {\n+  var user = saveUser(attrs);\n+  welcomeUser(user);\n+};\n+\n+// чистая\n+var signUp = function(Db, Email, attrs) {\n+  return function() {\n+    var user = saveUser(Db, attrs);\n+    welcomeUser(Email, user);\n+  };\n+};\n+```\n+\n+The example here demonstrates that the pure function must be honest about its dependencies and, as such, tell us exactly what it's up to. Just from its signature, we know that it will use a `Db`, `Email`, and `attrs` which should be telling to say the least.\n+\n+Этот пример показывает, что чистая функция должна быть полностью откровенна по отношению к своим зависимостям и, тем самым, иллюстрирует нам своё предназначение. Просто посмотрев на сигнатуру функции мы по меньшей мере можем понять, что она использует `Db`, `Email` и `attrs`.\n+\n+We'll learn how to make functions like this pure without merely deferring evaluation, but the point should be clear that the pure form is much more informative than its sneaky impure counterpart which is up to God knows what.\n+\n+Мы научимся писать такие чистые функции, даже без использования отложенного выполнения. Надеюсь, вам уже стало ясно, что чистая функция гораздо более информативна, чем подозрительная нечистая, намерения которой не ясны.\n+\n+Something else to notice is that we're forced to \"inject\" dependencies, or pass them in as arguments, which makes our app much more flexible because we've parameterized our database or mail client or what have you[^Don't worry, we'll see a way to make this less tedious than it sounds]. Should we choose to use a different Db we need only to call our function with it. Should we find ourselves writing a new application in which we'd like to reuse this reliable function, we simply give this function whatever `Db` and `Email` we have at the time.\n+\n+Хочу также отметить, что мы вынуждены «внедрять» зависимости, или передавать их в качестве аргументов, что делает наше приложение куда более гибким, за счёт параметризации вашего приложения-клиента к базе данных или почтового клиента (или что у вас там за приложение?)[^Не волнуйтесь, мы научимся делать это менее скучно, чем это звучит]. Если вы хотите поменять базу данных, то вам всего-навсего потребуется вызвать функцию, передав новую базу в качестве аргумента. Когда вы будете писать новое приложение и захотите переиспользовать нашу надёжную чистую функцию, вы можете просто передать ей те `Db` и `Email`, которые актуальны для вас.\n+\n+In a JavaScript setting, portability could mean serializing and sending functions over a socket. It could mean running all our app code in web workers. Portability is a powerful trait.\n+\n+В среде JavaScript портативность может значить сериализацию и отправку функции через сокет или же запуск всего нашего приложения с помощью Web Worker'ов. Портативность — мощная штука.\n+\n+Contrary to \"typical\" methods and procedures in imperative programming rooted deep in their environment via state, dependencies, and available effects, pure functions can be run anywhere our hearts desire.\n+\n+В отличие от «традиционных» методов и процедур в императивном программировании, которые жёстко связаны с состоянием системы, зависимостями и доступными эффектами, чистые функции могут использовать везде, где нашей душе угодно.\n+\n+When was the last time you copied a method into a new app? One of my favorite quotes comes from Erlang creator, Joe Armstrong: \"The problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana... and the entire jungle\".\n+\n+Вспомните последний раз, когда вы копировали метод из одного приложения в другое. Давно это было? Одна из моих самых любимых цитат была произнесена создателем языка Erlang, Джое Армстронгом: «Проблема объектно-ориентированных языков в неявной среде, которая их окружает. Вы хотели получить банан, а получили гориллу с бананом... И все джунгли».\n+\n+### Testable\n+### Тестирумость\n+\n+Next, we come to realize pure functions make testing much easier. We don't have to mock a \"real\" payment gateway or setup and assert the state of the world after each test. We simply give the function input and assert output.\n+\n+Дальше — больше, тестировать чистые функции проще. Вам больше не потребуется симулировать «реальный» платёжный шлюз или настраивать и строить предположения по поводу состояния всего мира во время каждого теста.\n+\n+In fact, we find the functional community pioneering new test tools that can blast our functions with generated input and assert that properties hold on the output. It's beyond the scope of this book, but I strongly encourage you to search for and try *Quickcheck* - a testing tool that is tailored for a purely functional environment.\n+\n+# FIXME\n+Функциональное сообщество создаёт новые инструменты для тестирования, которые могут очень серьёзно ускорить работу тестов с помощью генерации аргументов и предположений по значению функции. Это вне рамок этой книги, но я крайне рекомендую поискать в интернете и попробовать *Quickcheck* — инструмент для тестирования, написанный как раз для функциональной среды.\n+\n+### Reasonable\n+### Разумность\n+\n+Many believe the biggest win when working with pure functions is *referential transparency*. A spot of code is referentially transparent when it can be substituted for its evaluated value without changing the behavior of the program.\n+\n+Многие считают одним из главных преимуществ чистых функций *прозрачность ссылок*. Участок когда можно считать «ссылочно-прозрачным», когда его можно заменить на вычисленный им результат и при этом поведение программы не изменится.\n+\n+Since pure functions always return the same output given the same input, we can rely on them to always return the same results and thus preserve referential transparency. Let's see an example.\n+\n+Поскольку чистые функции всегда возвращают один и тот же результат, для одинаковых аргументов — они сохраняют прозрачность ссылок. Давайте обратимся к примеру.\n+\n+```js\n+\n+var decrementHP = function(player) {\n+  return player.set(\"hp\", player.hp-1);\n+};\n+\n+var isSameTeam = function(player1, player2) {\n+  return player1.team === player2.team;\n+};\n+\n+var punch = function(player, target) {\n+  if(isSameTeam(player, target)) {\n+    return target;\n+  } else {\n+    return decrementHP(target);\n+  }\n+};\n+\n+var jobe = Immutable.Map({name:\"Jobe\", hp:20, team: \"red\"});\n+var michael = Immutable.Map({name:\"Michael\", hp:20, team: \"green\"});\n+\n+punch(jobe, michael);\n+//=> Immutable.Map({name:\"Michael\", hp:19, team: \"green\"})\n+```\n+\n+`decrementHP`, `isSameTeam` and `punch` are all pure and therefore referentially transparent. We can use a technique called *equational reasoning* wherein one substitutes \"equals for equals\" to reason about code. It's a bit like manually evaluating the code without taking into account the quirks of programmatic evaluation. Using referential transparency, let's play with this code a bit.\n+\n+Функции `decrementHP`, `isSameTeam` и `punch` являются чистыми и, следовательно, ссылочно-прозрачными. Мы можем воспользоваться техникой *рассуждения о равном*, в которой мы заменяем равное равным, чтобы анализировать код. Это примерно то же самое, что и в уме просчитывать код, не учитывая тонкостей его программной реализации. Давай поиграем с кодом, используя прозрачность ссылкок.\n+\n+First we'll inline the function `isSameTeam`.\n+\n+Начнём с того, что встроим функцию `isSameTeam` в `punch`.\n+\n+```js\n+var punch = function(player, target) {\n+  if(player.team === target.team) {\n+    return target;\n+  } else {\n+    return decrementHP(target);\n+  }\n+};\n+```\n+\n+Since our data is immutable, we can simply replace the teams with their actual value\n+\n+Так как наши данные не меняются, то мы просто заменим переменные `team` на их значения.\n+\n+```js\n+var punch = function(player, target) {\n+  if(\"red\" === \"green\") {\n+    return target;\n+  } else {\n+    return decrementHP(target);\n+  }\n+};\n+```\n+\n+We see that it is false in this case so we can remove the entire if branch\n+\n+Заметим, что условие всегда ложно и избавимся от него:\n+\n+```js\n+var punch = function(player, target) {\n+  return decrementHP(target);\n+};\n+\n+```\n+\n+And if we inline `decrementHP`, we see that, in this case, punch becomes a call to decrement the `hp` by 1.\n+\n+И, если мы встроим `decrementHP`, мы поймём, что вызов функции `punch` становится вызовом функции по уменьшению ХП на 1 единицу.\n+\n+```js\n+var punch = function(player, target) {\n+  return target.set(\"hp\", target.hp-1);\n+};\n+```\n+\n+This ability to reason about code is terrific for refactoring and understanding code in general. In fact, we used this technique to refactor our flock of seagulls program. We used equational reasoning to the properties of addition and multiplication. Indeed, we'll be using these techniques throughout the book.\n+\n+Способность анализировать код таким образом чрезвычайно удобна для рефакторинга и понимания того, что код на самом деле делает. Мы уже пользовались этой техникой ранее, для рефакторинга нашей программы про стаи чаек (свойства сложения и умножения)\n+\n+### Parallel Code\n+### Параллелизм\n+\n+Finally, and here's the coup de grâce, we can run any pure function in parallel since it does not need access to shared memory and it cannot, by definition, have a race condition due to some side effect.\n+\n+В конце концов, сейчас будет вишнка на торте, мы можем запустить любую чистую функцию параллельно, так как ей не нужен доступ в общую память и она по определению привести к состоянию гонки из-за какого-либо побочного эффекта.\n+\n+This is very much possible in a server side js environment with threads as well as in the browser with web workers though current culture seems to avoid it due to complexity when dealing with impure functions.\n+\n+Это вполне применимо к потоковому JS на сервере, как и к браузерному с использованием web workers, хотя их особенно и не используют из-за сложностей, возникающих при работе с нечистыми функциями.","path":"ch3-ru.md","position":432,"original_position":432,"commit_id":"688c18c84df327a053e66017926b3ba277522c1e","original_commit_id":"688c18c84df327a053e66017926b3ba277522c1e","user":{"login":"abbakumov","id":6272189,"avatar_url":"https://avatars.githubusercontent.com/u/6272189?v=3","gravatar_id":"","url":"https://api.github.com/users/abbakumov","html_url":"https://github.com/abbakumov","followers_url":"https://api.github.com/users/abbakumov/followers","following_url":"https://api.github.com/users/abbakumov/following{/other_user}","gists_url":"https://api.github.com/users/abbakumov/gists{/gist_id}","starred_url":"https://api.github.com/users/abbakumov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/abbakumov/subscriptions","organizations_url":"https://api.github.com/users/abbakumov/orgs","repos_url":"https://api.github.com/users/abbakumov/repos","events_url":"https://api.github.com/users/abbakumov/events{/privacy}","received_events_url":"https://api.github.com/users/abbakumov/received_events","type":"User","site_admin":false},"body":"...вполне применимо как к потоковому JS на сервере, так и к ...","created_at":"2015-09-11T14:35:16Z","updated_at":"2015-09-11T14:35:16Z","html_url":"https://github.com/MostlyAdequate/mostly-adequate-guide-ru/pull/4#discussion_r39276899","pull_request_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/pulls/4","_links":{"self":{"href":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/pulls/comments/39276899"},"html":{"href":"https://github.com/MostlyAdequate/mostly-adequate-guide-ru/pull/4#discussion_r39276899"},"pull_request":{"href":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/pulls/4"}}},"pull_request":{"url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/pulls/4","id":44349832,"html_url":"https://github.com/MostlyAdequate/mostly-adequate-guide-ru/pull/4","diff_url":"https://github.com/MostlyAdequate/mostly-adequate-guide-ru/pull/4.diff","patch_url":"https://github.com/MostlyAdequate/mostly-adequate-guide-ru/pull/4.patch","issue_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/issues/4","number":4,"state":"open","locked":false,"title":"Chapter3","user":{"login":"maksimf","id":860283,"avatar_url":"https://avatars.githubusercontent.com/u/860283?v=3","gravatar_id":"","url":"https://api.github.com/users/maksimf","html_url":"https://github.com/maksimf","followers_url":"https://api.github.com/users/maksimf/followers","following_url":"https://api.github.com/users/maksimf/following{/other_user}","gists_url":"https://api.github.com/users/maksimf/gists{/gist_id}","starred_url":"https://api.github.com/users/maksimf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maksimf/subscriptions","organizations_url":"https://api.github.com/users/maksimf/orgs","repos_url":"https://api.github.com/users/maksimf/repos","events_url":"https://api.github.com/users/maksimf/events{/privacy}","received_events_url":"https://api.github.com/users/maksimf/received_events","type":"User","site_admin":false},"body":"","created_at":"2015-09-07T12:21:21Z","updated_at":"2015-09-11T14:35:16Z","closed_at":null,"merged_at":null,"merge_commit_sha":"836988a3ba978882820408b85d7439b9b7e6c289","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/pulls/4/commits","review_comments_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/pulls/4/comments","review_comment_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/pulls/comments{/number}","comments_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/issues/4/comments","statuses_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/statuses/688c18c84df327a053e66017926b3ba277522c1e","head":{"label":"MostlyAdequate:chapter3","ref":"chapter3","sha":"688c18c84df327a053e66017926b3ba277522c1e","user":{"login":"MostlyAdequate","id":14079115,"avatar_url":"https://avatars.githubusercontent.com/u/14079115?v=3","gravatar_id":"","url":"https://api.github.com/users/MostlyAdequate","html_url":"https://github.com/MostlyAdequate","followers_url":"https://api.github.com/users/MostlyAdequate/followers","following_url":"https://api.github.com/users/MostlyAdequate/following{/other_user}","gists_url":"https://api.github.com/users/MostlyAdequate/gists{/gist_id}","starred_url":"https://api.github.com/users/MostlyAdequate/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MostlyAdequate/subscriptions","organizations_url":"https://api.github.com/users/MostlyAdequate/orgs","repos_url":"https://api.github.com/users/MostlyAdequate/repos","events_url":"https://api.github.com/users/MostlyAdequate/events{/privacy}","received_events_url":"https://api.github.com/users/MostlyAdequate/received_events","type":"Organization","site_admin":false},"repo":{"id":41765171,"name":"mostly-adequate-guide-ru","full_name":"MostlyAdequate/mostly-adequate-guide-ru","owner":{"login":"MostlyAdequate","id":14079115,"avatar_url":"https://avatars.githubusercontent.com/u/14079115?v=3","gravatar_id":"","url":"https://api.github.com/users/MostlyAdequate","html_url":"https://github.com/MostlyAdequate","followers_url":"https://api.github.com/users/MostlyAdequate/followers","following_url":"https://api.github.com/users/MostlyAdequate/following{/other_user}","gists_url":"https://api.github.com/users/MostlyAdequate/gists{/gist_id}","starred_url":"https://api.github.com/users/MostlyAdequate/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MostlyAdequate/subscriptions","organizations_url":"https://api.github.com/users/MostlyAdequate/orgs","repos_url":"https://api.github.com/users/MostlyAdequate/repos","events_url":"https://api.github.com/users/MostlyAdequate/events{/privacy}","received_events_url":"https://api.github.com/users/MostlyAdequate/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/MostlyAdequate/mostly-adequate-guide-ru","description":"Mostly adequate guide to FP (in javascript, translated in russian)","fork":false,"url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru","forks_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/forks","keys_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/keys{/key_id}","collaborators_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/teams","hooks_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/hooks","issue_events_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/issues/events{/number}","events_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/events","assignees_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/assignees{/user}","branches_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/branches{/branch}","tags_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/tags","blobs_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/git/refs{/sha}","trees_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/git/trees{/sha}","statuses_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/statuses/{sha}","languages_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/languages","stargazers_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/stargazers","contributors_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/contributors","subscribers_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/subscribers","subscription_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/subscription","commits_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/commits{/sha}","git_commits_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/git/commits{/sha}","comments_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/comments{/number}","issue_comment_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/issues/comments{/number}","contents_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/contents/{+path}","compare_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/compare/{base}...{head}","merges_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/merges","archive_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/downloads","issues_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/issues{/number}","pulls_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/pulls{/number}","milestones_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/milestones{/number}","notifications_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/labels{/name}","releases_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/releases{/id}","created_at":"2015-09-01T21:47:19Z","updated_at":"2015-09-09T21:02:19Z","pushed_at":"2015-09-11T12:52:52Z","git_url":"git://github.com/MostlyAdequate/mostly-adequate-guide-ru.git","ssh_url":"git@github.com:MostlyAdequate/mostly-adequate-guide-ru.git","clone_url":"https://github.com/MostlyAdequate/mostly-adequate-guide-ru.git","svn_url":"https://github.com/MostlyAdequate/mostly-adequate-guide-ru","homepage":null,"size":4111,"stargazers_count":7,"watchers_count":7,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":1,"forks":3,"open_issues":1,"watchers":7,"default_branch":"master"}},"base":{"label":"MostlyAdequate:master","ref":"master","sha":"9e53b6d41c8eaa3f5681ec30b7c7f569ea72f9a3","user":{"login":"MostlyAdequate","id":14079115,"avatar_url":"https://avatars.githubusercontent.com/u/14079115?v=3","gravatar_id":"","url":"https://api.github.com/users/MostlyAdequate","html_url":"https://github.com/MostlyAdequate","followers_url":"https://api.github.com/users/MostlyAdequate/followers","following_url":"https://api.github.com/users/MostlyAdequate/following{/other_user}","gists_url":"https://api.github.com/users/MostlyAdequate/gists{/gist_id}","starred_url":"https://api.github.com/users/MostlyAdequate/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MostlyAdequate/subscriptions","organizations_url":"https://api.github.com/users/MostlyAdequate/orgs","repos_url":"https://api.github.com/users/MostlyAdequate/repos","events_url":"https://api.github.com/users/MostlyAdequate/events{/privacy}","received_events_url":"https://api.github.com/users/MostlyAdequate/received_events","type":"Organization","site_admin":false},"repo":{"id":41765171,"name":"mostly-adequate-guide-ru","full_name":"MostlyAdequate/mostly-adequate-guide-ru","owner":{"login":"MostlyAdequate","id":14079115,"avatar_url":"https://avatars.githubusercontent.com/u/14079115?v=3","gravatar_id":"","url":"https://api.github.com/users/MostlyAdequate","html_url":"https://github.com/MostlyAdequate","followers_url":"https://api.github.com/users/MostlyAdequate/followers","following_url":"https://api.github.com/users/MostlyAdequate/following{/other_user}","gists_url":"https://api.github.com/users/MostlyAdequate/gists{/gist_id}","starred_url":"https://api.github.com/users/MostlyAdequate/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MostlyAdequate/subscriptions","organizations_url":"https://api.github.com/users/MostlyAdequate/orgs","repos_url":"https://api.github.com/users/MostlyAdequate/repos","events_url":"https://api.github.com/users/MostlyAdequate/events{/privacy}","received_events_url":"https://api.github.com/users/MostlyAdequate/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/MostlyAdequate/mostly-adequate-guide-ru","description":"Mostly adequate guide to FP (in javascript, translated in russian)","fork":false,"url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru","forks_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/forks","keys_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/keys{/key_id}","collaborators_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/teams","hooks_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/hooks","issue_events_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/issues/events{/number}","events_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/events","assignees_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/assignees{/user}","branches_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/branches{/branch}","tags_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/tags","blobs_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/git/refs{/sha}","trees_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/git/trees{/sha}","statuses_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/statuses/{sha}","languages_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/languages","stargazers_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/stargazers","contributors_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/contributors","subscribers_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/subscribers","subscription_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/subscription","commits_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/commits{/sha}","git_commits_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/git/commits{/sha}","comments_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/comments{/number}","issue_comment_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/issues/comments{/number}","contents_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/contents/{+path}","compare_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/compare/{base}...{head}","merges_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/merges","archive_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/downloads","issues_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/issues{/number}","pulls_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/pulls{/number}","milestones_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/milestones{/number}","notifications_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/labels{/name}","releases_url":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/releases{/id}","created_at":"2015-09-01T21:47:19Z","updated_at":"2015-09-09T21:02:19Z","pushed_at":"2015-09-11T12:52:52Z","git_url":"git://github.com/MostlyAdequate/mostly-adequate-guide-ru.git","ssh_url":"git@github.com:MostlyAdequate/mostly-adequate-guide-ru.git","clone_url":"https://github.com/MostlyAdequate/mostly-adequate-guide-ru.git","svn_url":"https://github.com/MostlyAdequate/mostly-adequate-guide-ru","homepage":null,"size":4111,"stargazers_count":7,"watchers_count":7,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":1,"forks":3,"open_issues":1,"watchers":7,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/pulls/4"},"html":{"href":"https://github.com/MostlyAdequate/mostly-adequate-guide-ru/pull/4"},"issue":{"href":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/issues/4"},"comments":{"href":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/issues/4/comments"},"review_comments":{"href":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/pulls/4/comments"},"review_comment":{"href":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/pulls/4/commits"},"statuses":{"href":"https://api.github.com/repos/MostlyAdequate/mostly-adequate-guide-ru/statuses/688c18c84df327a053e66017926b3ba277522c1e"}}}}