--- 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 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)