diff --git a/modules/10-basics/10-hello-world/ru/README.md b/modules/10-basics/10-hello-world/ru/README.md index 9fa47ee..05b62b5 100644 --- a/modules/10-basics/10-hello-world/ru/README.md +++ b/modules/10-basics/10-hello-world/ru/README.md @@ -3,6 +3,6 @@ Elixir – динамический, функциональный язык пр Эликсир работает поверх виртуальной машины языка эрланг. Она широко известна своими уникальными возможностями для создания отказоустойчивых и распределенных систем. Причем, как во встраиваемых устройствах, например роутерах, так и в вебе, при создании приложений реального времени (игры, мессенджеры). -Практически все, что говорится про эликсир, является заслугой виртуальной машины эрланга. Эликсир задумывался как язык, который привносит в мир эрланга кое-что новое, чего не хватало самому эрлангу. В первую очередь это средства, повышающие уровень абстракции (Struct, Protocol), позволяющие писать более лаконичный код (оператор pipe, конструкция with), и удобно управлять проектом и его зависимостями (mix). Кроме того, это метапрограммирование -- мощная система макросов, позволяющая создавать DSL-языки. Хорошим примером такого DSL-языка является библиотека Ecto для работы с базами данных. +Практически все, что говорится про эликсир, является заслугой виртуальной машины эрланга. Эликсир задумывался как язык, который привносит в мир эрланга кое-что новое, чего не хватало самому эрлангу. В первую очередь это средства, повышающие уровень абстракции (Struct, Protocol), позволяющие писать более лаконичный код (оператор pipe, конструкция with), и удобно управлять проектом и его зависимостями (mix). Кроме того, это метапрограммирование -- мощная система макросов, позволяющая создавать DSL-языки. Хорошим примером такого DSL-языка является библиотека Ecto для работы с базами данных. -Эликсир – практичный язык. Он прост в освоении и эффективен в работе. На его базе создан веб-фреймворк Phoenix, очень напоминающий упрощенный Ruby On Rails. Его код открыт и доступен на гитхабе. Было бы несправедливо не сделать обучение по Elixir именно тут) +Эликсир – практичный язык. Он прост в освоении и эффективен в работе. На его базе создан веб-фреймворк Phoenix, очень напоминающий упрощенный Ruby On Rails. Его код открыт и доступен на гитхабе. diff --git a/modules/10-basics/20-modules/ru/README.md b/modules/10-basics/20-modules/ru/README.md index 6b8d55d..b63d508 100644 --- a/modules/10-basics/20-modules/ru/README.md +++ b/modules/10-basics/20-modules/ru/README.md @@ -34,7 +34,7 @@ end HexletBasics.Application.hello() ``` -Один модуль встроенный в Эликсир является особенным. Это модуль _Kernel_. Функции этого модуля можно вызывать напрямую, без указания самого модуля: +Один модуль, встроенный в Эликсир, является особенным. Это модуль _Kernel_. Функции этого модуля можно вызывать напрямую, без указания самого модуля: ```elixir is_number(13) # true diff --git a/modules/20-data-types/10-atoms-and-tuples/ru/EXERCISE.md b/modules/20-data-types/10-atoms-and-tuples/ru/EXERCISE.md index 0688607..a5edad5 100644 --- a/modules/20-data-types/10-atoms-and-tuples/ru/EXERCISE.md +++ b/modules/20-data-types/10-atoms-and-tuples/ru/EXERCISE.md @@ -12,11 +12,13 @@ Уже реализованная функция distance может вам пригодиться: ```elixir +point = {:point, 50, 50} Solution.is_point_inside_circle(point, {:circle, {:point, 10, 10}, 100}) # => true Solution.is_point_inside_circle(point, {:circle, {:point, -10, -10}, 20}) # => false +point = {:point, -10, 20} Solution.is_point_inside_rect(point, {:rect, {:point, -20, 30}, {:point, 20, 10}}) # => true Solution.is_point_inside_rect(point, {:rect, {:point, 0, 0}, {:point, 10, 10}}) diff --git a/modules/30-flow/40-function-clause/ru/README.md b/modules/30-flow/40-function-clause/ru/README.md index b243f9f..8682b80 100644 --- a/modules/30-flow/40-function-clause/ru/README.md +++ b/modules/30-flow/40-function-clause/ru/README.md @@ -1,7 +1,7 @@ В Эликсир одна функция может иметь несколько тел -- несколько разных блоков кода. В зависимости от входящих аргументов выполняется только один из этих блоков. -По английски термин "тело функции" пишется *clause* и произносится `[klôz]`. Поскольку это короче, то все Эликсир разработчики предпочитают говорить "клоз" вместо "тело функции". +По-английски термин "тело функции" пишется *clause* и произносится `[klôz]`. Поскольку это короче, то все Эликсир разработчики предпочитают говорить "клоз" вместо "тело функции". ```elixir def handle({:dog, name}, :add) do diff --git a/modules/40-collections/10-map/ru/EXERCISE.md b/modules/40-collections/10-map/ru/EXERCISE.md index d7f7dc9..38bbb91 100644 --- a/modules/40-collections/10-map/ru/EXERCISE.md +++ b/modules/40-collections/10-map/ru/EXERCISE.md @@ -1,4 +1,4 @@ -Реализуйте функцию `zip`, которая группирует элементы переданных векторов в подвектора. Если вектора отличаются длиной, то вместо сгрупированного элемента оставьте `nil`. Для обращения к элементу списка по индексу используйте `Enum.at`. +Реализуйте функцию `zip`, которая группирует элементы переданных векторов в подвектора. Если вектора отличаются длиной, то вместо сгруппированного элемента оставьте `nil`. Для обращения к элементу списка по индексу используйте `Enum.at`. Примеры: ```elixir diff --git a/modules/45-structs/20-typespecs/ru/README.md b/modules/45-structs/20-typespecs/ru/README.md index 47df6a2..9a3926b 100644 --- a/modules/45-structs/20-typespecs/ru/README.md +++ b/modules/45-structs/20-typespecs/ru/README.md @@ -1,7 +1,7 @@ Для продолжения обсуждения `протоколов` и `поведения`, нам нужно ознакомиться с типизацией в Elixir. -Elixir - динамически типизированный язык, поэтому все типы в Elixir проверяются во время выполнения. Тем не менее, Elixir поставляется со *спецификациями*, которые представляют собой нотацию, используемую для: +Elixir - динамически типизированный язык, поэтому все типы в Elixir проверяются во время выполнения. Тем не менее Elixir поставляется со *спецификациями*, которые представляют собой нотацию, используемую для: - объявления типизированных сигнатур функций (также называемых спецификациями); - объявления пользовательских типов. diff --git a/modules/45-structs/30-behaviour/ru/README.md b/modules/45-structs/30-behaviour/ru/README.md index b5eac6b..a6c34a3 100644 --- a/modules/45-structs/30-behaviour/ru/README.md +++ b/modules/45-structs/30-behaviour/ru/README.md @@ -96,4 +96,4 @@ defp find_parser(ext, parsers) do end ``` -Можно вызвать необходимый парсер напрямую или сделать словарь, где ключем будет нужное расширение файла, а значением нужный модуль парсера, однако *поведение* в этом дает чуть больше гарантий, что функции модулей реализованы соответствующим образом. +Можно вызвать необходимый парсер напрямую или сделать словарь, где ключём будет нужное расширение файла, а значением нужный модуль парсера, однако *поведение* в этом дает чуть больше гарантий, что функции модулей реализованы соответствующим образом. diff --git a/modules/55-processes/30-processes-state/ru/README.md b/modules/55-processes/30-processes-state/ru/README.md index 12f8715..bafe115 100644 --- a/modules/55-processes/30-processes-state/ru/README.md +++ b/modules/55-processes/30-processes-state/ru/README.md @@ -1,5 +1,5 @@ -В прошлом упражнении мы создали процесс-калькулятор, который только обрабатывает входящие запросы, не храня никакого *состояния*. Но как его сохранить? Основная идея процесса, который обрабатывает более одного сообщения за раз, это вызов рекурсивной функции, которая продолжит основной цикл обработки сообщений. Рассмотрим пример с процессом-счетчиком: +В прошлом упражнении мы создали процесс-калькулятор, который только обрабатывает входящие запросы, не храня никакого *состояния*. Но как его сохранить? Основная идея процесса, который обрабатывает более одного сообщения за раз, это вызов рекурсивной функции. Повторный вызов которой, продолжит основной цикл обработки сообщений. Рассмотрим пример с процессом-счетчиком: ```elixir defmodule Counter do diff --git a/modules/55-processes/50-supervisors/ru/EXERCISE.md b/modules/55-processes/50-supervisors/ru/EXERCISE.md index 67da30f..e89df8e 100644 --- a/modules/55-processes/50-supervisors/ru/EXERCISE.md +++ b/modules/55-processes/50-supervisors/ru/EXERCISE.md @@ -1,7 +1,7 @@ Супервизоры могут задаваться через модули, для этого нужно в модуле использовать поведение `Supervisor` и определить функцию обратного вызова `init/1`, которая будет вызвана при запуске супервизора через `start_link`. В файле с решением описано два агента, ваша задача дописать модуль `Solution`, добавив две функции: - `start_link` - функция для запуска супервизора из модуля -- `init` - функция, которая запустится перед стартом супервизора, в котором указывается список потомков, стратегия перезапуска и т.д. +- `init` - функция, которая запустится перед стартом супервизора, в неё передается список потомков, стратегия перезапуска и т.д. В функции `init` сделайте потомками `Decrementor` и `Incrementor`, а в стратегии перезапуска укажите `:one_for_one`. diff --git a/modules/55-processes/50-supervisors/ru/README.md b/modules/55-processes/50-supervisors/ru/README.md index 07a4477..7322146 100644 --- a/modules/55-processes/50-supervisors/ru/README.md +++ b/modules/55-processes/50-supervisors/ru/README.md @@ -116,7 +116,7 @@ Supervisor.which_children(pid) Зачастую используются стратегии `:one_for_one` и `:rest_for_one`. -Помимо стратегии перезапуска, в супервизоре можно указать, каким образом завершать наблюдаемые процессы. А точнее, какой сигнал выхода отправить процессу при, например, перезапуске. Можно указать приоритет у процессов потомков, например, если есть какой-то важный процесс потомок, без которого супервизия не имеет смысла и после завершения работы этого потомка супервизор получает сигнал от этого процесса и супервизор завершает работу (process shutdown). Об этом можно подробнее почитать в [официальной документации](https://hexdocs.pm/elixir/Supervisor.html#module-supervisor-strategies-and-options). Тепрерь посмотрим на примере, как работает стратегия `:one_for_all`: +Помимо стратегии перезапуска, в супервизоре можно указать, каким образом завершать наблюдаемые процессы. А точнее, какой сигнал выхода отправить процессу при, например, перезапуске. Можно указать приоритет у процессов потомков, например, если есть какой-то важный процесс потомок, без которого супервизия не имеет смысла и после завершения работы этого потомка супервизор получает сигнал от этого процесса и супервизор завершает работу (process shutdown). Об этом можно подробнее почитать в [официальной документации](https://hexdocs.pm/elixir/Supervisor.html#module-supervisor-strategies-and-options). Теперь посмотрим на примере, как работает стратегия `:one_for_all`: ```elixir {:ok, supervisor_pid} = Supervisor.start_link([{Counter, 0}], strategy: :one_for_one) diff --git a/modules/55-processes/55-process-registration/ru/EXERCISE.md b/modules/55-processes/55-process-registration/ru/EXERCISE.md index e01dab3..ade9ddb 100644 --- a/modules/55-processes/55-process-registration/ru/EXERCISE.md +++ b/modules/55-processes/55-process-registration/ru/EXERCISE.md @@ -1,5 +1,5 @@ -Допишите агента, добавив функции `add`, `drop` для регистрации/снятия процессов с учета и функцию `list_registered`, которая выводит список процессов, которые зарегистрированы через агента. Если процесс завершился, то при вызове `add` регистрировать процесс не нужно. Если удаляемый процесс не существует, то нужно вернуть `:ok`, учтите, что `Process.unregister` вызывает исключение при попытке удалить несуществующий процесс. +Допишите агента, добавив функции `add`, `drop` для регистрации/снятия процессов с учета и функцию `list_registered`, которая выводит список процессов, зарегистрированных через агента. Если процесс завершился, то при вызове `add` регистрировать процесс не нужно. Если удаляемый процесс не существует, то нужно вернуть `:ok`, учтите, что `Process.unregister` вызывает исключение при попытке удалить несуществующий процесс. ```elixir ProcessRegister.start_link() diff --git a/modules/55-processes/60-genservers/ru/README.md b/modules/55-processes/60-genservers/ru/README.md index 8f78d67..50ea6b1 100644 --- a/modules/55-processes/60-genservers/ru/README.md +++ b/modules/55-processes/60-genservers/ru/README.md @@ -1,5 +1,5 @@ -Генсерверы являются основным строительным кирпичиком OTP. Генсервер - это процесс, который может хранить состояние, выполнять какой-либо код, не обязательно синхронно и т.д. Отличие обычных процессов от обобщенных серверных процессов (general servers) в том, что разработчики OTP заранее подготовили все необходимое, что зачастую нужно для работы с процессом. Например, обработка ошибок, написание функций обратного вызова, встраивание в дерево супервизии. +Генсерверы являются основным строительным кирпичиком OTP. Генсервер - это процесс, который может хранить состояние, выполнять какой-либо код, не обязательно синхронно и т.д. Отличие обычных процессов от обобщенных серверных процессов (general servers) в том, что разработчики OTP заранее подготовили все необходимое, что зачастую нужно для работы с процессом. Например, обработка ошибок, написание функций обратного вызова, встраивание в дерево супервизии. Возникает вопрос, а в чем разница между `Agent` и `GenServer`, ведь с первого взгляда они делают одно и то же. Разница в том, что абстракция `Agent` построена на основе `GenServer`, например в `Agent` управление состоянием происходит через функцию `Agent.update`, в то время как у `GenServer` состоянием нужно управлять вручную. Абстракция агентов построена вокруг какого-либо *состояния*, в то время как генсервер может и не обладать состоянием, а только выполнять какую-либо работу. @@ -101,7 +101,7 @@ iex(48)> b GenServer # .............. ``` -Важно понимать, что обработчики `handle_call`, `handle_cast` и `handle_info` при определении завязываются на конкретные сообщения, которые они обрабатывают, поэтому важно описать паттерн catch all, который перехватит сообщения, которые генсервер не знает как обработать. Если же не описать обобщенный вариант обработки сообщения, то процесс генсервер аварийно завершится при таком вызове: +Важно понимать, что обработчики `handle_call`, `handle_cast` и `handle_info` при определении завязываются на конкретные сообщения, которые они обрабатывают, поэтому важно описать паттерн-матч функцию catch all. Эта функция перехватит сообщения, которые генсервер не знает как обработать. Если же не описать обобщенный вариант обработки сообщения, то процесс генсервер аварийно завершится при таком вызове: ```elixir GenServer.call(Counter, :do_something_different) diff --git a/modules/60-macros/40-macros-hygiene/ru/README.md b/modules/60-macros/40-macros-hygiene/ru/README.md index 3e79f3e..29fe28f 100644 --- a/modules/60-macros/40-macros-hygiene/ru/README.md +++ b/modules/60-macros/40-macros-hygiene/ru/README.md @@ -1,5 +1,5 @@ -При создании макросов важно соблюдать их гигиену, так как макросы, которые модифицируют окружение, могут сильно навредить. Негигиеничные макросы еще сложнее понимать и отлаживать, потому что они меняют окружение, в котором исполняется код. Для устранения таких проблем в разных языках добавлены специальные возможности по упрощению создания гигиеничных макросов, Elixir в том числе. +При создании макросов важно соблюдать их гигиену, так как макросы, которые модифицируют окружение, могут сильно навредить. Негигиеничные макросы еще сложнее понимать и отлаживать, потому что они меняют окружение, в котором исполняется код. Для устранения таких проблем в разных языках добавлены специальные возможности по упрощению создания гигиеничных макросов, Elixir, в том числе. По умолчанию, в Elixir макросы гигиеничны, поэтому можно не переживать за контекст, в котором макрос используется: diff --git a/modules/60-macros/50-macros-ast/ru/EXERCISE.md b/modules/60-macros/50-macros-ast/ru/EXERCISE.md index bf6fae2..a8ae598 100644 --- a/modules/60-macros/50-macros-ast/ru/EXERCISE.md +++ b/modules/60-macros/50-macros-ast/ru/EXERCISE.md @@ -1,5 +1,5 @@ -Создайте функцию `collect_module_stats`, которая принимает строку, в которой определяется модуль и функции модуля, а затем подсчитывается статистика по функциям, которые определены. +Создайте функцию `collect_module_stats` принимающую строку, в которой определяется модуль и функции модуля, а затем подсчитывается статистика по функциям, определенные внутри модуля. Для начала, изучите функцию `string_to_quoted` модуля `Code` и функцию `prewalk` из модуля `Macro`. Формат собираемой статистики представлен в примерах: