learnxinyminutes-docs/ru/erlang.md
2024-12-08 23:20:53 -07:00

254 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
contributors:
- ["Giovanni Cappellotto", "http://www.focustheweb.com/"]
translators:
- ["Nikita Kalashnikov", "https://root.yuuzukiyo.net/"]
filename: learnerlang-ru.erl
---
```erlang
% Символ процента предваряет однострочный комментарий.
%% Два символа процента обычно используются для комментариев к функциям.
%%% Три символа процента используются для комментариев к модулям.
% Пунктуационные знаки, используемые в Erlang:
% Запятая (`,`) разделяет аргументы в вызовах функций, структурах данных и
% образцах.
% Точка (`.`) (с пробелом после неё) разделяет функции и выражения в
% оболочке.
% Точка с запятой (`;`) разделяет выражения в следующих контекстах:
% формулы функций, выражения `case`, `if`, `try..catch` и `receive`.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 1. Переменные и сопоставление с образцом.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Num = 42. % Все названия переменных начинаются с большой буквы.
% Erlang использует единичное присваивание переменным. Если вы попытаетесь
% присвоить другое значение переменной `Num`, вы получите ошибку.
Num = 43. % ** exception error: no match of right hand side value 43
% В большинстве языков `=` обозначает операцию присвоения. В отличие от них, в
% Erlang `=` — операция сопоставления с образцом. `Lhs = Rhs` на самом
% деле подразумевает «вычисли правую часть выражения (Rhs) и затем сопоставь
% результат с образцом слева (Lhs)».
Num = 7 * 6.
% Числа с плавающей точкой.
Pi = 3.14159.
% Атомы используются для представления различных нечисловых констант. Названия
% атомов начинаются с буквы в нижнем регистре, за которой могут следовать другие
% буквы английского алфавита, цифры, символ подчёркивания (`_`) или «собака»
% (`@`).
Hello = hello.
OtherNode = example@node.
% Если в имени атома нужно использовать другие символы, кроме допустимых,
% имя атома необходимо взять в одинарные кавычки (`'`).
AtomWithSpace = 'some atom with space'.
% Кортежы подобны структурам в языке C.
Point = {point, 10, 45}.
% Если нужно извлечь определённые данные из кортежа, используется оператор
% сопоставления с образцом — `=`.
{point, X, Y} = Point. % X = 10, Y = 45
% Символ `_` может использоваться как «заполнитель» для переменных, значения
% которых в текущем выражении нас не интересуют. Он называется анонимной
% переменной. В отличие от остальных переменных, множественные использования
% `_` в одном образце не требуют, чтобы все значения, присваевыемые этой
% переменной, были идентичными.
Person = {person, {name, {first, joe}, {last, armstrong}}, {footsize, 42}}.
{_, {_, {_, Who}, _}, _} = Person. % Who = joe
% Список создаётся путём заключения его элементов в квадратные скобки и
% разделения их запятыми. Отдельные элементы списка могут быть любого типа.
% Первый элемент списка называется головой списка. Список, получающийся в
% результате отделения головы, называется хвостом списка.
ThingsToBuy = [{apples, 10}, {pears, 6}, {milk, 3}].
% Если `T` — список, то `[H|T]` — тоже список, где `H` является головой, а `T` —
% хвостом. Вертикальная черта (`|`) разделяет голову и хвост списка.
% `[]` — пустой список.
% Мы можем извлекать элементы из списка с помощью сопоставления с образцом.
% Если у нас есть непустой список `L`, тогда выражение `[X|Y] = L`, где `X` и
% `Y` — свободные (не связанные с другими значениям) переменные, извлечёт голову
% списка в `X` и его хвост в `Y`.
[FirstThing|OtherThingsToBuy] = ThingsToBuy.
% FirstThing = {apples, 10}
% OtherThingsToBuy = {pears, 6}, {milk, 3}
% В Erlang нет строк как отдельного типа. Все используемые в программах строки
% являются обычным списком целых чисел. Строковые значения всегда должны быть в
% двойных кавычках (`"`).
Name = "Hello".
[72, 101, 108, 108, 111] = "Hello".
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 2. Последовательное программирование.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Модуль — основная единица кода в Erlang. В них пишутся и сохраняются все
% функции. Модули хранятся в файлах с расширением `.erl`.
% Модули должны быть скомпилированы перед тем, как использовать код из них.
% Скомпилированный файл модуля имеет разрешение `.beam`.
-module(geometry).
-export([area/1]). % список функций, экспортируемых из модуля.
% Функция `area` состоит из двух формул (clauses). Формулы отделяются друг от
% друга точкой с запятой, после последнего определения должна стоять точка с
% пробелом после неё.
% Каждое определение имеет заголовок и тело. Заголовок состоит из названия
% функции и образца (в скобках); тело состоит из последовательных выражений,
% вычисляемых, когда аргументы функции совпадают с образцом в заголовке.
% Сопоставление с образцами в заголовках происходит в том порядке, в котором
% они перечислены в определении функции.
area({rectangle, Width, Ht}) -> Width * Ht;
area({circle, R}) -> 3.14159 * R * R.
% Компиляция файла с исходным кодом geometry.erl.
c(geometry). % {ok,geometry}
% Необходимо указывать имя модуля вместе с именем функции для определения, какую
% именно фукнцию мы хотим вызвать.
geometry:area({rectangle, 10, 5}). % 50
geometry:area({circle, 1.4}). % 6.15752
% В Erlang две функции с разной арностью (числом аргументов) в пределах одного
% модуля представляются как две разные функции.
-module(lib_misc).
-export([sum/1]). % экспорт функции `sum` с арностью 1, принимающую один аргумент.
sum(L) -> sum(L, 0).
sum([], N) -> N;
sum([H|T], N) -> sum(T, H+N).
% Fun'ы — анонимные функции, называемые так по причине отсутствия имени. Зато
% их можно присваивать переменным.
Double = fun(X) -> 2*X end. % `Double` указывает на анонимную функцию с идентификатором: #Fun<erl_eval.6.17052888>
Double(2). % 4
% Функции могут принимать fun'ы как параметры и возвращать их в качестве
% результата вычислений.
Mult = fun(Times) -> ( fun(X) -> X * Times end ) end.
Triple = Mult(3).
Triple(5). % 15
% Выделения списоков (list comprehensions) — выражения, создающие списки без
% применения анонимных функций, фильтров или map'ов.
% Запись `[F(X) || X <- L]` значит «список `F(X)`, где `X` последовательно
% выбирается из списка `L`».
L = [1,2,3,4,5].
[2*X || X <- L]. % [2,4,6,8,10]
% В выделениях списков могут быть генераторы и фильтры для отделения подмножеств
% генерируемых значений.
EvenNumbers = [N || N <- [1, 2, 3, 4], N rem 2 == 0]. % [2, 4]
% Охранные выражения используются для простых проверок переменных в образцах,
% что значительно расширяет возможности сопоставления. Они могут использоваться
% в заголовках определений функций, предварённые ключевым словом `when`, а также
% в условных конструкциях.
max(X, Y) when X > Y -> X;
max(X, Y) -> Y.
% Охранные выражения можно группировать, разделяя запятой.
% Последовательность `GuardExpr1, GuardExpr2, ..., GuardExprN` является истинной
% только в том случае, когда все выражения, которые она содержат, являются
% истинными.
is_cat(A) when is_atom(A), A =:= cat -> true;
is_cat(A) -> false.
is_dog(A) when is_atom(A), A =:= dog -> true;
is_dog(A) -> false.
% Последовательность охранных выражений, разделённых точками с запятой, является
% истинной в том случае, если хотя бы одно выражение из списка `G1; G2; ...; Gn`
% является истинным.
is_pet(A) when is_dog(A); is_cat(A) -> true;
is_pet(A) -> false.
% Записи предоставляют возможность именования определённых элементов в кортежах.
% Определения записей могут быть включены в исходный код модулей Erlang или же
% в заголовочные файлы с расширением `.hrl`.
-record(todo, {
status = reminder, % Значение по умолчанию.
who = joe,
text
}).
% Для чтения определений записей из файлов в оболочке можно использовать команду
% `rr`.
rr("records.hrl"). % [todo]
% Создание и изменение записей.
X = #todo{}.
% #todo{status = reminder, who = joe, text = undefined}
X1 = #todo{status = urgent, text = "Fix errata in book"}.
% #todo{status = urgent, who = joe, text = "Fix errata in book"}
X2 = X1#todo{status = done}.
% #todo{status = done,who = joe,text = "Fix errata in book"}
% Условное выражение `case`.
% Функция `filter` возвращет список всех элементов `X` из списка `L`, для
% которых выражение `P(X)` является истинным.
filter(P, [H|T]) ->
case P(H) of
true -> [H|filter(P, T)];
false -> filter(P, T)
end;
filter(P, []) -> [].
filter(fun(X) -> X rem 2 == 0 end, [1, 2, 3, 4]). % [2, 4]
% Условное выражение `if`.
max(X, Y) ->
if
X > Y -> X;
X < Y -> Y;
true -> nil;
end.
% Внимание: в выражении `if` должно быть как минимум одно охранное выраженние,
% вычисляющееся в true, иначе возникнет исключение.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 3. Обработка исключений.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Исключения возникают в случае внутренних ошибок системы или вызываются
% непосредственно из кода программы с помощью вызовов `throw(Exception)`,
% `exit(Exception)` или `erlang:error(Exception)`.
generate_exception(1) -> a;
generate_exception(2) -> throw(a);
generate_exception(3) -> exit(a);
generate_exception(4) -> {'EXIT', a};
generate_exception(5) -> erlang:error(a).
% В Erlang есть два способа обработки исключений. Первый заключается в
% использовании выражения `try..catch` в функции, в которой возможен выброс
% исключения.
catcher(N) ->
try generate_exception(N) of
Val -> {N, normal, Val}
catch
throw:X -> {N, caught, thrown, X};
exit:X -> {N, caught, exited, X};
error:X -> {N, caught, error, X}
end.
% Второй способ заключается в использовании `catch`. Во время поимки исключения
% оно преобразуется в кортеж с информацией об ошибке.
catcher(N) -> catch generate_exception(N).
```
## Ссылки:
* ["Learn You Some Erlang for great good!"](http://learnyousomeerlang.com/)
* ["Programming Erlang: Software for a Concurrent World" by Joe Armstrong](http://pragprog.com/book/jaerlang/programming-erlang)
* [Erlang/OTP Reference Documentation](http://www.erlang.org/doc/)
* [Erlang - Programming Rules and Conventions](http://www.erlang.se/doc/programming_rules.shtml)