% Символ процента предваряет однострочный комментарий.
%% Два символа процента обычно используются для комментариев к функциям.
%%% Три символа процента используются для комментариев к модулям.
% Пунктуационные знаки, используемые в 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*Xend.% `Double` указывает на анонимную функцию с идентификатором: #Fun<erl_eval.6.17052888>
Double(2).% 4
% Функции могут принимать fun'ы как параметры и возвращать их в качестве
% результата вычислений.
Mult=fun(Times)->(fun(X)->X*Timesend)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],Nrem2==0].% [2, 4]
% Охранные выражения используются для простых проверок переменных в образцах,
% что значительно расширяет возможности сопоставления. Они могут использоваться
% в заголовках определений функций, предварённые ключевым словом `when`, а также
% в условных конструкциях.
max(X,Y)whenX>Y->X;max(X,Y)->Y.% Охранные выражения можно группировать, разделяя запятой.
% Последовательность `GuardExpr1, GuardExpr2, ..., GuardExprN` является истинной
% только в том случае, когда все выражения, которые она содержат, являются
% истинными.
is_cat(A)whenis_atom(A),A=:=cat->true;is_cat(A)->false.is_dog(A)whenis_atom(A),A=:=dog->true;is_dog(A)->false.% Последовательность охранных выражений, разделённых точками с запятой, является
% истинной в том случае, если хотя бы одно выражение из списка `G1; G2; ...; Gn`
% является истинным.
is_pet(A)whenis_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])->caseP(H)oftrue->[H|filter(P,T)];false->filter(P,T)end;filter(P,[])->[].filter(fun(X)->Xrem2==0end,[1,2,3,4]).% [2, 4]
% Условное выражение `if`.
max(X,Y)->ifX>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)->trygenerate_exception(N)ofVal->{N,normal,Val}catchthrow:X->{N,caught,thrown,X};exit:X->{N,caught,exited,X};error:X->{N,caught,error,X}end.% Второй способ заключается в использовании `catch`. Во время поимки исключения
% оно преобразуется в кортеж с информацией об ошибке.
catcher(N)->catchgenerate_exception(N).