Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Format docs and improve test examples #125

Merged
merged 8 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions modules/10-basics/70-interop/description.ru.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,15 @@ theory: |
# функция подсчитывающее количество слов из erlang
:string.words("Hello World")
# => ** (FunctionClauseError) no function clause matching in :string.strip_left/2
# =>
# =>
# => The following arguments were given to :string.strip_left/2:
# =>
# =>
# => # 1
# => "Hello World"
# =>
# =>
# => # 2
# => 32
# =>
# =>
# => (stdlib) string.erl:1661: :string.strip_left/2
# => (stdlib) string.erl:1659: :string.strip/3
# => (stdlib) string.erl:1597: :string.words/2
Expand Down
1 change: 1 addition & 0 deletions modules/10-basics/description.en.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
name: Elixir Basics
description: |

The Elixir language is quite complex. Most of its elements are more complex than they first appear. In the first module, we will look at modules and functions, basic data types and operations with them.
1 change: 0 additions & 1 deletion modules/20-data-types/30-maps/description.ru.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ theory: |
Map.delete(other_map, :a) # %{b: 2}
```


instructions: |

Реализуйте функцию `keys_sum`, которая принимает словарь и два ключа, извлекает значения по этим ключам, и возвращает сумму значений. Если ключа в словаре нет, то соответствующее значение не учитывается.
Expand Down
1 change: 1 addition & 0 deletions modules/20-data-types/description.en.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
name: Elixir data types
description: |

In the second module we will continue to get acquainted with different data types: atoms, tuples, lists and dictionaries. If you are not familiar with functional programming, even at this stage, some of it may already seem strange. But don't be frightened, it's not hard to use all of this.
34 changes: 20 additions & 14 deletions modules/30-flow/15-pattern-matching-for-maps/description.ru.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@ theory: |

```elixir
my_map = %{a: 1, b: 2, c: 3}
%{a: value} = my_map
%{a: value} = my_map

IO.puts(value) # => 1
```

Если ключи не являются атомами, то синтаксис отличается:

```elixir
my_map = %{"a" => 1, "b" => 2, "c" => 3}
%{"a" => value1} = my_map
IO.puts(value1) # => 1

%{"b" => value2, "c" => value3} = my_map
IO.puts(value2) # => 2
IO.puts(value3) # => 3
Expand All @@ -32,10 +34,11 @@ theory: |
```

Переменные можно использовать для извлечения значений, но не для извлечения ключей:

```elixir
%{"c" => my_var} = my_map
IO.puts(my_var) # => 3

%{my_var => 1} = my_map # ** (CompileError) iex:17: cannot use variable my_var as map key inside a pattern.
```

Expand All @@ -48,9 +51,9 @@ theory: |
```

_pin_ operator извлекает текущее значение переменной и подставляет его в шаблон. И дальше это значение в шаблоне работает как литерал.

_pin_ operator можно использовать и для ключа, и для значения:

```elixir
value1 = 1
%{"a" => ^value1} = my_map
Expand All @@ -67,18 +70,21 @@ instructions: |
Обе функции генерируют исключение `MatchError` если в словаре нет нужных ключей.

```elixir
defmodule Solution do
Solution.get_values(%{a: 1, b: 2})
# => {1, 2}
Solution.get_values(%{a: :ok, b: 42, c: true})
# => {:ok, 42}

def get_values(data) do
# TODO реализация
end
Solution.get_values(%{})
# => MatchError

def get_value_by_key(data, key) do
# TODO реализация
end
Solution.get_value_by_key(%{answer: 42}, :answer)
# => 42
Solution.get_value_by_key(%{question: "6 * 7"}, :question)
# => "6 * 7"

end
Solution.get_value_by_key(%{a: 1}, :b)
# => MatchError
```


tips: []
58 changes: 29 additions & 29 deletions modules/30-flow/20-case/description.ru.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ theory: |
Условные переходы в функциональных языках отличаются от императивных, потому что основаны на сопоставлении с образцом. Основная идея в том, что некое значение по очереди сравнивается с несколькими шаблонами, и в зависимости от того, с каким шаблоном оно совпадет, выполняется та или иная ветка кода.

Есть несколько вариантов условных переходов:
- конструкция case;
- конструкция cond;
- конструкция `case`;
- конструкция `cond`;
- тело функции (function clause);
- обработка исключений (rescue, catch);
- чтение сообщений из mailbox (receive).
- обработка исключений `rescue`, `catch`;
- чтение сообщений из mailbox `receive`.

Все они, кроме *cond*, реализуют эту идею.
Все они, кроме *cond*, реализуют эту идею.

## Рассмотрим конструкцию case.

Для примера рассмотрим вычисление наибольшего общего делителя:

```elixir
def gcd(a, b) do
case rem(a, b) do
Expand All @@ -26,24 +26,24 @@ theory: |
end
end
```

Здесь вычисляется значение `rem(a, b)` и сравнивается с двумя шаблонами. Первый шаблон -- литерал `0`. Если значение совпадает с ним, то выполняется код, завершающий рекурсию и возвращающий `b`. Второй шаблон -- переменная `c`. С этим шаблоном совпадут любые значения, и тогда выполняется вызов `gcd(b, c)`.

Второй пример:

```elixir
case Map.fetch(acc, word) do
{:ok, count} -> Map.put(acc, word, count + 1)
:error -> Map.put(acc, word, 1)
end
```

Здесь выполняется вызов функции `Map.fetch(acc, word)`. Получившееся значение сравнивается с двумя шаблонами и выполняется соответствующий код.

Шаблонов может быть несколько. И важен их порядок, потому что первый совпавший шаблон останавливает перебор оставшихся шаблонов. Если не совпал ни один из шаблонов, то генерируется исключение.

В общем виде конструкция *case* выглядит так:

```elixir
case Expr do
Pattern1 [when GuardSequence1] ->
Expand All @@ -53,11 +53,11 @@ theory: |
BodyN
end
```

Что такое GuardSequence -- цепочка охранных выражений, мы рассмотрим позже.

case могут быть вложенными друг в друга:

```elixir
def handle(animal, action) do
case animal do
Expand All @@ -76,7 +76,7 @@ theory: |
```

Вложенный даже на два уровня код плохо читается. Обычно этого можно избежать. Данный пример можно реализовать без вложенного case таким образом:

```elixir
def handle(animal, action) do
case {animal, action} do
Expand All @@ -90,7 +90,7 @@ theory: |

## Охранные выражения (Guards)

Теперь вернемся к упомянутым выше охранным выражениям.
Теперь вернемся к упомянутым выше охранным выражениям.

Не всегда достаточно шаблона, чтобы проверить все условия для ветвления в коде. Например, шаблоном нельзя проверить попадание числа в определенный диапазон.

Expand Down Expand Up @@ -118,31 +118,31 @@ theory: |
```elixir
when is_map(a) and map_size(a) > 10 ->
```

можно сразу писать:

```elixir
when map_size(a) > 10 ->
```

instructions: |

Реализовать функцию `join_game(user)`, которая принимает игрока в виде кортежа `{:user, name, age, role}` и определяет, разрешено ли данному игроку подключиться к игре. Если игроку уже исполнилось 18 лет, то он может войти в игру. Если роль игрока `:admin` или `:moderator`, то он может войти в игру независимо от возраста. Функция должна вернуть `:ok` или `:error`.

Реализовать функцию `move_allowed?(current_color, figure)` которая определяет, разрешено ли данной шахматной фигуре сделать ход. Параметр `current_color` может быть либо `:white` либо `:black`, и он указывает, фигурам какого цвета разрешено сделать ход. Параметр `figure` представлен кортежем `{type, color}`, где `type` может быть один из: `:pawn`, `:rock`, `:bishop`, `:knight`, `:queen`, `:king`, а color может быть `:white` или `:black`. Фигура может сделать ход если её тип `:pawn` или `:rock` и её цвет совпадает с `current_color`. Функция должна вернуть `true` или `false`.

```elixir
defmodule Solution do

def join_game(user) do
# TODO реализация
end

def move_allowed?(current_color, figure) do
# TODO реализация
end

end
```elixir
Solution.join_game({:user, "Bob", 17, :admin})
# => :ok
Solution.join_game({:user, "Bob", 17, :moderator})
# => :ok
Solution.join_game({:user, "Bob", 17, :member})
# => :error

Solution.move_allowed?(:white, {:pawn, :white})
# => true
Solution.move_allowed?(:black, {:pawn, :white})
# => false
```

tips: []
75 changes: 41 additions & 34 deletions modules/30-flow/30-cond/description.ru.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,23 @@ theory: |

```elixir
case Expr do
Pattern1 [when GuardSequence1] ->
Body1
...
PatternN [when GuardSequenceN] ->
BodyN
Pattern1 [when GuardSequence1] ->
Body1
...
PatternN [when GuardSequenceN] ->
BodyN
end
```

Стало:

```elixir
cond do
GuardSequence1 ->
Body1
...
GuardSequenceN ->
BodyN
GuardSequence1 ->
Body1
...
GuardSequenceN ->
BodyN
end
```

Expand All @@ -50,12 +50,12 @@ theory: |
num > 5 -> IO.puts("more than 5")
end
end

my_fun(20) # => more than 10
my_fun(8) # => more than 5
my_fun(3) # ** (CondClauseError) no cond clause evaluated to a truthy value
```


## Конструкция if

В Эликсир есть привычная всем конструкция *if*:
Expand Down Expand Up @@ -87,23 +87,26 @@ theory: |
Есть важное отличие от императивных языков -- в функциональных языках *if* всегда возвращает какое-то значение.

```elixir
> a = 5
> b = 10
> c = if a > b do
...> a
...> else
...> b
...> end
> IO.puts(c) # 10
a = 5
b = 10
c = if a > b do
a
else
b
end

IO.puts(c)
# => 10
```

Некоторые функциональные языки требуют, чтобы часть *else* всегда присутствовала, потому что значение нужно вернуть в любом случае, выполняется условие *if* или не выполняется. Эликсир этого не требует:

```elixir
> c = if a > b do
...> a
...> end
> IO.puts(c) # nil
c = if a > b do
a
end

IO.puts(c) # => nil
```

instructions: |
Expand All @@ -113,17 +116,21 @@ instructions: |
Реализовать функцию `double_win?(a_win, b_win, c_win)`, которая принимает 3 булевых параметра для трех игроков. Если победили игроки A и B, то функция возвращает атом `:ab`. Если победили игроки A и C, то функция возвращает атом `:ac`, если победили игроки B и C, то функция возвращает атом `:bc`. Во всех остальных случаях функция возвращает `false`.

```elixir
defmodule Solution do

def single_win?(a_win, b_win) do
# TODO реализация
end

def double_win?(a_win, b_win, c_win) do
# TODO реализация
end

end
Solution.single_win?(true, false)
# => true
Solution.single_win?(false, true)
# => true
Solution.single_win?(true, true)
# => false

Solution.double_win?(true, true, false)
# => :ab
Solution.double_win?(true, false, true)
# => :ac
Solution.double_win?(true, true, true)
# => false
Solution.double_win?(true, false, false)
# => false
```

tips: []
Loading
Loading