From d0ea0538d50467f87f2a57e3d0c5401586bfac45 Mon Sep 17 00:00:00 2001 From: Artem Solomatin Date: Tue, 21 Jan 2025 22:29:21 +0300 Subject: [PATCH 01/16] Fix task description --- modules/20-data-types/10-atoms-and-tuples/ru/EXERCISE.md | 2 ++ 1 file changed, 2 insertions(+) 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}}) From 74ceed9b306e55bbff1c9d3a93ffd911efd0ca6a Mon Sep 17 00:00:00 2001 From: Artem Solomatin Date: Tue, 21 Jan 2025 22:32:29 +0300 Subject: [PATCH 02/16] Update README.md --- modules/60-macros/40-macros-hygiene/ru/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 макросы гигиеничны, поэтому можно не переживать за контекст, в котором макрос используется: From e8a7cac366ead4f9d3f6ac394b6f490bc4aaa614 Mon Sep 17 00:00:00 2001 From: Artem Solomatin Date: Tue, 21 Jan 2025 22:33:25 +0300 Subject: [PATCH 03/16] Update README.md --- modules/55-processes/60-genservers/ru/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/55-processes/60-genservers/ru/README.md b/modules/55-processes/60-genservers/ru/README.md index 8f78d67..315912b 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` состоянием нужно управлять вручную. Абстракция агентов построена вокруг какого-либо *состояния*, в то время как генсервер может и не обладать состоянием, а только выполнять какую-либо работу. From c91e9a2af0d17b9fcfda4b88a8584f8323b989fa Mon Sep 17 00:00:00 2001 From: Artem Solomatin Date: Tue, 21 Jan 2025 22:35:22 +0300 Subject: [PATCH 04/16] Update README.md --- modules/55-processes/60-genservers/ru/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/55-processes/60-genservers/ru/README.md b/modules/55-processes/60-genservers/ru/README.md index 315912b..50ea6b1 100644 --- a/modules/55-processes/60-genservers/ru/README.md +++ b/modules/55-processes/60-genservers/ru/README.md @@ -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) From ec364847c497568ac2696ca7804a687e1d4c7d6e Mon Sep 17 00:00:00 2001 From: Artem Solomatin Date: Tue, 21 Jan 2025 22:36:45 +0300 Subject: [PATCH 05/16] Update EXERCISE.md --- modules/55-processes/55-process-registration/ru/EXERCISE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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() From 2127959293a89e89e7be8701fe0743b44266e4e8 Mon Sep 17 00:00:00 2001 From: Artem Solomatin Date: Tue, 21 Jan 2025 22:37:22 +0300 Subject: [PATCH 06/16] Update README.md --- modules/55-processes/50-supervisors/ru/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) From 4865cae03e75cef270b93ad54f953c7107af4d29 Mon Sep 17 00:00:00 2001 From: Artem Solomatin Date: Tue, 21 Jan 2025 22:38:16 +0300 Subject: [PATCH 07/16] Update EXERCISE.md --- modules/55-processes/50-supervisors/ru/EXERCISE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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`. From dd00ebfb96b45cd32a6a331a0fbc9581d83f1cf9 Mon Sep 17 00:00:00 2001 From: Artem Solomatin Date: Tue, 21 Jan 2025 22:40:06 +0300 Subject: [PATCH 08/16] Update README.md --- modules/55-processes/30-processes-state/ru/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 2834758ace73f520a63200c9fa798c4800388a37 Mon Sep 17 00:00:00 2001 From: Artem Solomatin Date: Tue, 21 Jan 2025 22:41:59 +0300 Subject: [PATCH 09/16] Update README.md --- modules/45-structs/30-behaviour/ru/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 ``` -Можно вызвать необходимый парсер напрямую или сделать словарь, где ключем будет нужное расширение файла, а значением нужный модуль парсера, однако *поведение* в этом дает чуть больше гарантий, что функции модулей реализованы соответствующим образом. +Можно вызвать необходимый парсер напрямую или сделать словарь, где ключём будет нужное расширение файла, а значением нужный модуль парсера, однако *поведение* в этом дает чуть больше гарантий, что функции модулей реализованы соответствующим образом. From 5cabcea000a3d5a76bdfc9dedb685bd329a9e729 Mon Sep 17 00:00:00 2001 From: Artem Solomatin Date: Tue, 21 Jan 2025 22:42:56 +0300 Subject: [PATCH 10/16] Update README.md --- modules/45-structs/20-typespecs/ru/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 поставляется со *спецификациями*, которые представляют собой нотацию, используемую для: - объявления типизированных сигнатур функций (также называемых спецификациями); - объявления пользовательских типов. From a40de0746a5319da4c552e4698d7e35340243b52 Mon Sep 17 00:00:00 2001 From: Artem Solomatin Date: Thu, 23 Jan 2025 01:55:07 +0300 Subject: [PATCH 11/16] Update README.md --- modules/10-basics/10-hello-world/ru/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/10-basics/10-hello-world/ru/README.md b/modules/10-basics/10-hello-world/ru/README.md index 9fa47ee..b73455d 100644 --- a/modules/10-basics/10-hello-world/ru/README.md +++ b/modules/10-basics/10-hello-world/ru/README.md @@ -5,4 +5,4 @@ Elixir – динамический, функциональный язык пр Практически все, что говорится про эликсир, является заслугой виртуальной машины эрланга. Эликсир задумывался как язык, который привносит в мир эрланга кое-что новое, чего не хватало самому эрлангу. В первую очередь это средства, повышающие уровень абстракции (Struct, Protocol), позволяющие писать более лаконичный код (оператор pipe, конструкция with), и удобно управлять проектом и его зависимостями (mix). Кроме того, это метапрограммирование -- мощная система макросов, позволяющая создавать DSL-языки. Хорошим примером такого DSL-языка является библиотека Ecto для работы с базами данных. -Эликсир – практичный язык. Он прост в освоении и эффективен в работе. На его базе создан веб-фреймворк Phoenix, очень напоминающий упрощенный Ruby On Rails. Его код открыт и доступен на гитхабе. Было бы несправедливо не сделать обучение по Elixir именно тут) +Эликсир – практичный язык. Он прост в освоении и эффективен в работе. На его базе создан веб-фреймворк Phoenix, очень напоминающий упрощенный Ruby On Rails. Его код открыт и доступен на гитхабе. From fa3500b8b303c9ce264d02b79b02cf5e68ee7d53 Mon Sep 17 00:00:00 2001 From: Artem Solomatin Date: Thu, 23 Jan 2025 01:55:42 +0300 Subject: [PATCH 12/16] Update README.md --- modules/10-basics/10-hello-world/ru/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/10-basics/10-hello-world/ru/README.md b/modules/10-basics/10-hello-world/ru/README.md index b73455d..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. Его код открыт и доступен на гитхабе. From f70eae8b73ae5defc84ce5ebd9dadfb3cd6714e7 Mon Sep 17 00:00:00 2001 From: Artem Solomatin Date: Thu, 23 Jan 2025 01:57:12 +0300 Subject: [PATCH 13/16] Update README.md --- modules/10-basics/20-modules/ru/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From bf9645d2f121b42dd112af03825ab17e4b173c42 Mon Sep 17 00:00:00 2001 From: Artem Solomatin Date: Thu, 23 Jan 2025 01:59:09 +0300 Subject: [PATCH 14/16] Update README.md --- modules/30-flow/40-function-clause/ru/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 0e3283c2a1d887bbedfb62bc341a04a6a70d1ba3 Mon Sep 17 00:00:00 2001 From: Artem Solomatin Date: Thu, 23 Jan 2025 02:00:25 +0300 Subject: [PATCH 15/16] Update EXERCISE.md --- modules/40-collections/10-map/ru/EXERCISE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 5d864086389b4c841b58d87b81e5bea799bd8c92 Mon Sep 17 00:00:00 2001 From: Artem Solomatin Date: Thu, 23 Jan 2025 02:02:58 +0300 Subject: [PATCH 16/16] Update EXERCISE.md --- modules/60-macros/50-macros-ast/ru/EXERCISE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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`. Формат собираемой статистики представлен в примерах: