2013-08-24 20:54:31 +04:00
|
|
|
|
---
|
|
|
|
|
language: erlang
|
|
|
|
|
contributors:
|
|
|
|
|
- ["Giovanni Cappellotto", "http://www.focustheweb.com/"]
|
2013-09-13 21:28:48 +04:00
|
|
|
|
translators:
|
2013-08-24 20:54:31 +04:00
|
|
|
|
- ["Nikita Kalashnikov", "https://root.yuuzukiyo.net/"]
|
|
|
|
|
filename: learnerlang-ru.erl
|
|
|
|
|
lang: ru-ru
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
```erlang
|
|
|
|
|
% Символ процента предваряет однострочный комментарий.
|
|
|
|
|
|
|
|
|
|
%% Два символа процента обычно используются для комментариев к функциям.
|
|
|
|
|
|
|
|
|
|
%%% Три символа процента используются для комментариев к модулям.
|
|
|
|
|
|
|
|
|
|
% Пунктуационные знаки, используемые в Erlang:
|
|
|
|
|
% Запятая (`,`) разделяет аргументы в вызовах функций, структурах данных и
|
|
|
|
|
% образцах.
|
2015-10-14 11:17:09 +03:00
|
|
|
|
% Точка (`.`) (с пробелом после неё) разделяет функции и выражения в
|
2013-08-24 20:54:31 +04:00
|
|
|
|
% оболочке.
|
|
|
|
|
% Точка с запятой (`;`) разделяет выражения в следующих контекстах:
|
|
|
|
|
% формулы функций, выражения `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)
|