[перевірена версія][перевірена версія]
Вилучено вміст Додано вміст
виправив помилку
Вирізав елементи та тексти які псували енциклопедичність статті. Там було багато жаргону, сленгу та термінів програміста зі стажем.
Рядок 124:
Синтаксис успадкований від мови [[Prolog]]. Підтримує [[модульне програмування|модулі]], [[поліморфізм (програмування)|поліморфні функції]], зіставлення за шаблоном, [[Анонімна функція|анонімні функції]], умовні конструкції, структури, [[обробка винятків|обробку винятків]], оптимізацію [[Хвостова рекурсія|хвостової рекурсії]].
 
Головна риса Erlang  — модель легких процесів. Процеси є дешевими, їхнє створення вимагає таку кількість ресурсів, що їх можна порівняти з викликом функції. Єдиним способом взаємодії процесів є асинхронний обмін повідомленнями. Процес може встановити зв'язок (link) з іншими процесами і за вибором або отримувати повідомлення про їхнє дострокове завершення з вказанням причини або розділити їхню долю. Процес має свою «поштову скриню», звідки може вибірково читати повідомлення. Мова програмування Erlang сприяє створенню великої кількості [[Конкуррентність|конкурентних]] процесів. Процеси ізольовані та не мають спільного стану.
 
Процес проєктування полягає в ітеративному розбитті системи на ієрархії підсистем, які конкурентно взаємодіють, доки складові не стануть достатньо простими для реалізації.
Рядок 135:
Erlang є [[Декларативне програмування|декларативною мовою програмування]], яка використовується більше для опису того, ''що'' має бути обчислено, ніж ''як''. Наприклад, визначення функції, яке використовує [[Зіставляння зі взірцем|зіставлення зі зразком]] для вибору одного з варіантів обчислення або вилучення елемента даних зі складової структури нагадує [[рівняння]]. [[Зіставляння зі взірцем|Зіставлення зі взірцем]] поширене навіть на бітові рядки, що спрощує реалізацію телекомунікаційних протоколів.<ref name=":1" />
 
[[функція|Функції]] є [[Об'єкт першого класу|об'єктами першого класу]] Erlang. У мові також широко застосовуються характерні для [[Функційне програмування|функціональної парадигми]] програмування [[Спискові вирази|спискові включення]] (генератори списків).<ref name=":1" />[[Файл:Обмін повідомленнями в мові Erlang.png|міні|421x421пкс|Обмін повідомленнями в мові Erlang]]
 
==== Паралельні обчислення ====
[[Файл:Обмін повідомленнями в мові Erlang.png|міні|421x421пкс|Обмін повідомленнями в мові Erlang]]
Особливістю мови Erlang є застосування '''''легковагих процесів''''' відповідно до [[Модель акторів|моделі акторів]]. Такий підхід дозволяє виконувати одночасно сотні тисяч і навіть мільйони таких процесів, кожен з яких може мати скромні вимоги до [[Оперативна пам'ять|пам'яті]]. Процеси ізольовані один від одного і не мають загального стану, але між ними можна встановити зв'язок та отримувати повідомлення про їхній стан.<ref name=":1" />
 
Для взаємодії процесів використовують асинхронний обмін повідомленнями. Кожен процес має свою [[Черга (структура даних)|чергу]] повідомлень, обробка якої використовує [[Зіставляння зі взірцем|зіставлення із взірцем]]. Процес, що надіслав повідомлення, не отримує повідомлення про доставку, навіть якщо ідентифікатор процесу одержувача недійсний або одержувач ігнорує повідомлення. Таким чином, відповідальність за правильно організовану взаємодію між процесами лежить на розробникові.<ref name=":2" />
 
Наприклад, при реалізації на Erlang мережевого [[чат]]у, структура програми може безпосередньо відображати одночасність дій користувачів щодо обміну повідомленнями шляхом запуску нових процесів. Ефективність передачі повідомлень зберігається зі збільшенням кількості процесів, а вимоги до пам'яті мінімізуються за рахунок того, що легковагими процесами керує віртуальна машина, а не засоби [[Операційна система|операційної системи]].<ref name=":1" />
 
==== Розподілені обчислення ====
Erlang з самого початку проєктувався для [[Розподілені обчислення|розподілених обчислень]] та [[Масштабовність|масштабованості]]. Підтримка паралелізму вбудована в [[Синтаксис (програмування)|синтаксис]] та [[Семантика мов програмування|семантику]] мови, тому побудову системи можна вести, абстрагуючись від конкретного місця обчислень. У стандартній поставці Erlang може налагодити зв'язок процесів протоколу [[TCP/IP]] незалежно від підтримуваних ним платформ ([[Операційна система|операційних систем]]).<ref name=":1" />
 
Запущений екземпляр емулятора Erlang називається [[Вузол (інформатика)|вузлом]] (node). Вузол має ім'я і «знає» про існування інших вузлів на цій машині або у мережі. Створення та взаємодія процесів різних вузлів не відрізняється від взаємодії процесів всередині вузла. Програми, написані на Erlang, здатні працювати на кількох вузлах. Вузлами можуть бути процесори, багато [[Ядро мікропроцесора|ядер]] одного [[процесор]]а, і навіть цілий кластер машин. Для створення процесу на іншому вузлі процесу достатньо знати його ім'я і, без особливих підстав, він може не цікавитися фізичним розташуванням процесу, що з ним взаємодіє. Синтаксис відправки повідомлення процесу на своєму вузлі та віддаленому однаковий.<ref name=":1" />
 
Завдяки вбудованим у мову можливостям розподілених обчислень об'єднання в [[Комп'ютерний кластер|кластер]], [[балансування навантаження]], додавання вузлів та серверів, підвищення надійності викликають лише невеликі витрати на додатковий код. За замовчуванням, вузли спроєктовані для роботи всередині відокремленого сегмента мережі ([[Демілітаризована зона (комп'ютерні мережі)|DMZ]]), але, якщо необхідно, комунікація між вузлами може відбуватися із застосуванням протоколу [[SSL]], захищеного [[Криптографія|криптографічними методами]].<ref name=":1" />
 
==== М'який реальний час ====
Програми високорівневою мовою Erlang можуть бути використані в системах [[Реальний час|м'якого реального часу]] (який іноді перекладають як «псевдореальний» або «квазіреальний»). Автоматизоване керування пам'яттю та [[збирання сміття]] діють у рамках одного процесу, що дає можливість створювати системи з мілісекундним [[Час відповіді|часом відгуку]] (навіть незважаючи на необхідність збирання сміття), що не відчувають погіршення [[Пропускна здатність (обчислення)|пропускної здатності]] при високому навантаженні.<ref name=":1" />
 
==== Гаряча заміна коду ====
Для систем, які не можуть бути зупинені для [[Оновлення програмного забезпечення|оновлення коду]], Erlang пропонує гарячу заміну коду ({{Lang-en|hot code upgrade}}). При цьому в додатку можуть одночасно працювати старі і нові версії коду. У такий спосіб програмне забезпечення на Erlang може бути модернізовано без простоїв, а виявлені помилки виправлені.<ref name=":5">{{Cite web|url=http://ftp.sunet.se/pub/lang/erlang/white_paper.html|title=Open-source Erlang — White Paper|last=Armstrong, Däcker, Lindgren, Millroth|first=Erlang product team at Ericsson.|date=2013|website=http://ftp.sunet.se/pub/lang/erlang/white_paper.html|publisher=Ericsson AB|language=англійська|archiveurl=https://web.archive.org/web/20111025022940/http://ftp.sunet.se/pub/lang/erlang/white_paper.html}}</ref>
 
== Програмування на Erlang ==
== Опис мови ==
 
=== Інтерактивна оболонка ===
==== Типи даних ====
[[Файл:Інтерактивна оболонка erl в окремому вікні.png|міні|333x333пкс|Інтерактивна оболонка erl в окремому вікні]]
[[Сильна і слабка типізація|Типізація в Erlang є сильною]] та [[Динамічна типізація|динамічною]]. Динамічна типізація була обрана для мови Erlang через те, що перші розробники були більше з нею знайомі.<ref name=":3">{{Cite book
Інтерактивна оболонка ({{Lang-en|shell}}) для Erlang може бути викликана в [[UNIX-подібні операційні системи|Unix-подібних системах]] командою <code>erl</code>, у Windows&nbsp;— <code>werl</code>.
|title=Learn You Some Erlang for Great Good!: A Beginner's Guide
|last=Hébert
|first=Fred
|year=2013
|publisher=No Starch Press
|pages=624
|language=англійська
|isbn=ISBN 978-1593274351.
}}</ref> На думку Джо Армстронга, статична типізація вимагала б дуже великих трудовитрат, зокрема, реалізувати систему гарячого дозавантаження коду було б дуже важко. Така [[Сильна і слабка типізація|типізація]], коли можливі помилки типів виявляються лише під час виконання, не завадила можливості створювати системи з дуже [[висока доступність|високим рівнем доступності]]. Дані Erlang є ''незмінними'': операції не переписують старі значення, що знаходяться в пам'яті. Якщо необхідно, модулі на Erlang можна забезпечити описами та визначеннями нових типів (що не впливають на компіляцію програми) для автоматичної перевірки типів за допомогою утиліти Dialyzer.<ref name=":3" />
 
Оболонка дозволяє:
==== Числа ====
У Erlang є два типи числових [[Літерал (програмування)|літералів]]: ''цілі'' і з ''рухомою комою'', наприклад: <code>125</code>,<code>4.5e-20</code>. Крім звичайної нотації, числа можна задавати через символ [[ASCII]] (наприклад, <code>$B</code> означає <code>66</code>) або разом із зазначенням системи числення з основою від 2 до 36 (у старих версіях&nbsp;— до 16), наприклад: <code>16#3f</code>, <code>2#1010</code>. У Erlang застосовуються цілі числа [[Довга арифметика|довільної точності]] та [[Дійсне число|дійсні числа]] подвійної точності (64 [[біт]]и), у стандарті [[IEEE 754-2008|IEEE 754—1985]]. Для роботи з числами можна використовувати модуль <code>math</code>, який містить звичайний набір математичних функцій та функцію <code>math:pi/0</code>, що повертає [[Число пі|число <math>\pi</math>]].<ref name=":6">{{Cite web|url=https://www.erlang.org/doc/man/math.html|title=math, STDLIB Reference Manual Version 1.19.3|website=https://www.erlang.org/doc/man/math.html|language=англійська}}</ref> Приклад обчислень в інтерактивній оболонці:<syntaxhighlight lang="erlang" line="1">
Erlang/OTP 23 [erts-11.2.2.4] [source] [64-bit] [smp:20:20] [ds:20:20:10] [async-threads:1] [hipe]
 
* вводити вирази та отримувати результат їх виконання, випробувати новий код,
Eshell V11.2.2.4 (abort with ^G)
* займатися інтерактивним налагодженням,
1> 123 / 23 + 12 * (2 + 3).
* керувати системою, що знаходиться в промисловій експлуатації, тощо.<ref name=":4">{{Cite book
65.34782608695652
2> math:cos(math:pi()).
-1.0
3> random:uniform(10).
5
</syntaxhighlight>
 
==== Атоми ====
''Атом''&nbsp;— константа з ім'ям, що має бути взята в одинарні лапки, якщо не починається з малої літери або містить знаки, окрім літер, цифр, підкреслення, крапки та символу<code>@</code>. Поняття атома запозичене з [[Пролог|Prolog]] та його можна вважати аналогом [[Перелічуваний тип даних|перерахувань]] (enum) в інших мовах програмування (без необхідності попередньої декларації).{{Sfn|Martin Logan, et al|2011|с=31—32}} Атоми використовуються майже виключно в порівняннях (та в [[Зіставляння зі взірцем|зіставленні зі взірцем]] (en: Pattern matching)), та мають Erlang дуже ефективну реалізацію. Крім того, деякі атоми мають певний сенс у значеннях, що повертаються, і описі винятків. До них відносяться, наприклад: <code>error</code>, <code>ignore</code>, <code>noreply</code>, <code>ok</code>, <code>reply</code>, <code>stop</code>, <code>undefined</code>.
 
==== Бітові рядки та бінарні дані ====
''Бітовий рядок'' використовується для зберігання пам'яті нетипізованих даних. Рядки, що складаються з цілої кількості [[Октет (інформатика)|октетів]], називаються ''бінарними'' (або ''двійковими'') ''даними'' ({{Lang-en|binaries}}). Синтаксис опису бітового рядка досить гнучкий, оскільки визначає значення бітів окремих діапазонів і може бути забезпечений модифікатором типу.<ref name=":1" /> Декілька прикладів в інтерактивній командній оболонці:
<syntaxhighlight lang="erlang" line="1">
1> <<23,89,120>>.
<<23,89,120>>
2> <<"ABC">>.
<<65,66,67>>
3> <<10,17,42:16>>.
<<10,17,0,42>>
4> <<$a, $b, $c>>.
<<"abc">>
5> <<1024/utf8>>.
<<208,128>>
</syntaxhighlight>
Конструктори бітових рядків ({{Lang-en|bitstring comprehension}}) аналогічні списковим генераторам, але працюють над бітовими рядками:
<syntaxhighlight line="1">
1> << <<bnot(X):1>> || <<X:1>> <= <<2#111011:6>> >>.
<<4:6>>
</syntaxhighlight>
У цьому прикладі змінна X послідовно отримує біти числа <code>2#111011</code>, які потім інвертуються операцією бітового заперечення <code>bnot</code> (від {{Lang-en|binary NOT}}), внаслідок чого виходить число 4.<ref name=":1" />
 
==== Кортеж ====
''[[Кортеж (інформатика)|Кортеж]]'' ({{Lang-en|tuple}})&nbsp;— складений тип даних з фіксованою кількістю елементів. При доступі до елементів кортежу за допомогою вбудованих функцій, нумерація елементів починається з одиниці, а не з нуля. Перший елемент кортежу (атом) можуть використовувати для опису ролі кортежу у програмі&nbsp;— його називають тегом ({{Lang-en|tag}}&nbsp;— «мітка»). В Erlang прийнято будувати різні типи даних на основі кортежів з тегами, це полегшує [[зневадження]] програми та вважається гарним стилем програмування.<ref name=":1" />
 
Для роботи з кортежами є декілька вбудованих функцій, наприклад:<ref name=":1" />
<syntaxhighlight lang="erlang" line="1">
1> tuple_size({a, 1, "777"}).
3
2> element(1, {b, 2, 3, 4}).
b
3> setelement(1, {c, 5}, d).
{d,5}
</syntaxhighlight>
 
==== Список ====
''Список'' ({{Lang-en|list}})&nbsp;— складений тип даних зі змінною кількістю елементів. Для маніпуляції зі списками можна використовувати функції модуля <code>[https://www.erlang.org/doc/man/lists.html#all-2 lists]</code> стандартної бібліотеки. Формально список визначається як структура, яка має голову ({{Lang-en|head}}) та хвіст ({{Lang-en|tail}}), що виражається синтаксично у вигляді <code>[HEAD|TAIL]</code>, де хвіст зазвичай є списком (можливо порожнім). Порожній список позначається <code>[]</code><ref name=":1" />
 
Списки можна записувати і більш звичним способом. Наступні записи еквівалентні:
<syntaxhighlight line="1">
1> [a|[b|[c|[]]]].
[a,b,c]
</syntaxhighlight>
Для роботи зі списками можна використовувати конструктори списків<ref name=":3" />(генератори списків&nbsp;— en: List Comprehensions), наприклад:
<syntaxhighlight lang="erlang" line="1">
1> [X / 2 || X <- [1,2,3,4]].
[0.5,1.0,1.5,2.0]
</syntaxhighlight>
Модуль <code>[https://www.erlang.org/doc/man/lists.html#all-2 lists]</code> стандартної бібліотеки містить функції для роботи зі списками (та рядками, оскільки рядок виду «test» в Erlang є списком кодів символів)<ref name=":1" />, такі як знаходження найбільшого значення, сортування, зміни порядку елементів на протилежний, отримання суми елементів тощо. У наступному прикладі «склеюємо» два списки в один за допомогою [[Конкатенація|конкатенації]], і далі розбиваємо на два списки функцією <code>lists:split/2</code>:
<syntaxhighlight lang="erlang" line="1">
1> lists:split(2, [l,2,3] ++ [4,5,6]).
{[l,2],[3,4,5,6]}
</syntaxhighlight>
А це приклад того, що рядок виду «test» в Erlang є списком кодів символів:
<syntaxhighlight lang="erlang" line="1">
1> "test" =:= [$t, $e, $s, $t].
true
2> "test" =:= [116, 101, 115, 116].
true
3> $t.
116
</syntaxhighlight>
 
У модулі <code>[https://www.erlang.org/doc/man/lists.html#all-2 lists]</code> є також набір [[Функція вищого порядку|функцій вищого порядку]], таких як <code>lists:all/2</code>, <code>lists:any/2</code>, <code>lists:dropwhile/2</code>, <code>lists:filter/2</code>, <code>lists:foldl/3</code>, <code>lists:foldr/3</code>, <code>lists:map/2</code>, <code>lists:foreach/2</code>.
 
<code>lists:map/2</code>&nbsp;— функція вищого порядку, яка дає можливість застосувати визначену нами функцію до кожного елемента списку, в результаті отримаємо новий список:
<syntaxhighlight lang="erlang" line="1">
third_degree(R) ->
lists:map(fun(X) -> math:pow(X, 3) end, R).
</syntaxhighlight>
В даному прикладі функція math: pow(X, 3) підносить до степеня 3 кожен елемент списку R.
 
<code>lists:filter/2</code>&nbsp;— дана функція вищого порядку приймає два параметри: функцію (предикат), за допомогою якої ми відфільтровуємо наш список&nbsp;— другий параметр. Повертає новий список&nbsp;— результат обробки фільтром вхідного списку.
<syntaxhighlight lang="erlang" line="1">
multiple_three(List) ->
lists:filter(fun(X) -> X rem 3 =:= 0 end, List).
</syntaxhighlight>
В даному прикладі з вхідного списку List у новий&nbsp;— вихідний список попадуть лише елементи, кратні трьом.<code>lists:foldl/3</code>&nbsp;— функція лівої згортки ([[Англійська мова|англ]]. fold&nbsp;— згорнути, «l» від англ. left&nbsp;— лівий) приймає 3 аргументи:
* функцію згортання
* початкове значення акумулятора
* перелік
Функція згортання приймає два аргументи: поточний елемент списку та поточне значення акумулятора. І повертає нове значення акумулятора.
 
Класичні приклади&nbsp;— обчислення суми та добутку елементів масиву:
<syntaxhighlight lang="erlang" line="1">
1> Numberlist = [11, 12, 13, 14, 15].
[11, 12, 13, 14, 15]
2> lists:foldl(fun(Item, Acc) -> Acc + Item end, 0, Numberlist).
65
3> lists:foldl(fun(Item, Acc) -> Acc * Item end, 1, Numberlist).
360360
</syntaxhighlight>
 
Наступний приклад ілюструє роботу функції правої згортки lists: foldr (англ. fold&nbsp;— згорнути, «r» від англ. right&nbsp;— правий), першим параметром якої має бути функція:
<syntaxhighlight lang="erlang">
1> D = fun(V, A) -> V / A end. % функція D - ділення V на A
#Fun<erl_eval.12.82930912>
2> lists:foldr(D, 1, [1, 2, 4, 8]).
0.25
3> 1/(2/(4/(8/1))).
0.25
</syntaxhighlight>
Результат виконання згортки справа наліво (у рядку 2) тотожний ланцюжковому поділу (рядок 3). Другий параметр <code>foldr</code>&nbsp;— початкове значення так званого акумулятора. Для кожного елемента списку (справа ліворуч) до елемента та акумулятора застосовується функція, задана першим аргументом <code>foldr</code>, а значення записується в акумулятор. За вичерпанням списку, функція повертає значення акумулятора. Функція є досить потужним засобом, якщо врахувати, що акумулятор може бути списком або кортежем.<ref name=":2" />
 
Зазвичай користуються foldl&nbsp;— тому, що операція отримання елементу-голови списку виконується за константний час, а для отримання елементу з кінця списку потрібно пройтись через весь список<ref name=":9" />.
 
==== Рядок ====
У Erlang немає самостійного типу для ''рядків''&nbsp;— внутрішньо рядки є списками кодів символів. Рядок <code>"Привіт!"</code> рівносильний (у відповідному кодуванні) списку <code>[1055,1088,1080,1074,1077,1090,33]</code>. Для правильної інтерпретації списків кодів символів як рядків в інтерактивній консолі&nbsp;— запускайте з відповідним параметром: <code>$ erl +pc unicode</code>. Erlang підтримує [[Юнікод|Unicode]] як у рядку, так і запису окремого символу (<code>$X</code>, де X&nbsp;— деякий символ).<ref name=":2" />
 
Бінарні послідовності записуються та відображаються, як послідовності цілих чисел або рядків, поміщені між подвійними символами <code><nowiki><</nowiki></code> та <code><nowiki>></nowiki></code>. Для прикладу:
<syntaxhighlight lang="erlang" line="1">
1> <<5,10,20>>.
<<5,10,20>>
2> <<"hello">>.
<<"hello">>
</syntaxhighlight>
<code>term_to_binary(Term) -> Bin</code>&nbsp;— Конвертує будь-який терм Erlang у бінарну послідовність.<ref name=":9" />
 
Бінарна послідовність, вироблена за допомогою term_to_binary, зберігається в так званому зовнішньому форматі терму. Терми, які були конвертовані в бінарні послідовності з використанням term_to_binary, можуть бути збережені в файли, передані в повідомленнях по мережі тощо, а початковий терм, з якого вони були зроблені, може бути відновлений пізніше. Це надзвичайно корисно для збереження складних структур даних у файли або надсилання складних структур даних на віддалені машини.<ref name=":9" />
<syntaxhighlight lang="erlang" line="1">
1> B = term_to_binary("useful").
<<131,107,0,6,117,115,101,102,117,108>>
2> binary_to_term(B).
"useful"
</syntaxhighlight>
Атоми і рядки зовні досить схожі, але мають різні реалізації. Тоді як атоми можна лише порівнювати, рядки підтримують багато інших операцій, їм є безліч функцій в модулях <code>lists</code> і <code>string</code>. Рядок може виконувати функції атома, але пам'ять, яку займає рядок, пропорційна його довжині, тоді як атоми зберігаються в системній таблиці і на кожне зберігання/пересилання атома в програмі припадає лише декілька байтів, незалежно від довжини атома. Порівняння двох атомів&nbsp;— це порівняння двох внутрішніх ідентифікаторів, яке виконується за одну операцію, тоді як порівняння рядків передбачає поелементний прохід, тобто порівняння кодів символів&nbsp;— елементів списків.<ref name=":1" />
 
==== Логічні значення ====
 
Для значень булевої логіки ''істинне'' та ''хибне'' в Erlang застосовуються атоми <code>true</code> (істинне) і <code>false</code> (хибне), які використовуються операціями порівняння, логічними операціями, вбудованими функціями.<ref name=":1" /> Приклад:
<syntaxhighlight lang="erlang" line="1">
1> 2 < 3.
true
2> is_boolean(125).
false
</syntaxhighlight>
 
==== Функціональний об'єкт (Fun) ====
<code>Fun-вираз</code> дозволяє створити анонімну функцію (лямбда-функцію), яка використовується, наприклад, для передачі аргументом в іншу функцію. За допомогою <code>fun</code> можна також отримати функціональний об'єкт для функції модуля.<ref name=":2" /> Приклади:
<syntaxhighlight lang="erlang" line="1">
1> lists:map(fun(X) -> X + 1 end, [1, 2, 3]).
[2,3,4]
2> Belongs = fun lists:member/2.
#Fun<lists.member.2>
3> Belongs(a, [a, b]).
true
</syntaxhighlight>
 
==== Запис ====
 
Щоб позначати окремі елементи кортежів (полегшити роботу з великими кортежами) і уникнути помилок при написанні програми, в Erlang було додано синтаксичний цукор&nbsp;— синтаксис ''[[Структура (тип даних)|записів]]'' ({{Lang-en|record}}). Записів не існує в час виконання&nbsp;— на етапі компіляції записи перетворюються (транслюються) в кортежі&nbsp;— ключі губляться, відповідно, в час виконання існують лише значення записів. Для роботи з записами, необхідно спочатку дати опис запису директивою <code>-record</code>, наприклад, для запису <code>user</code> опис може бути наступним<ref name=":4">{{Cite book
|title=Erlang and OTP in Action.
|last=Logan,Merritt, Carlsson.
Рядок 346 ⟶ 158:
|isbn=ISBN 9781933988788
}}</ref>
<syntaxhighlight lang="erlang" line="1">
-record(user, {login = "anonymous", email, password}).
</syntaxhighlight>
З цього опису компілятор дізнається, що маються на увазі кортежі з чотирьох елементів, в яких елементи з другого по четвертий відповідають полям <code>login</code>, <code>nick</code>, <code>password</code> запису з ім'ям <code>user</code> (визначається атомом в першому елементі кортежу). Значенням за замовчуванням для поля <code>login</code> є рядок <code>"anon"</code>. Якщо значення за замовчуванням не вказано явно, таким є атом <code>undefined</code>.
 
Також, оболонка дозволяє використовувати додаткові функції (команди), доступні тільки в ній. До прикладу, команда <code>q().</code> здійснює вихід із оболонки із завершенням всього, що робить Erlang-система.<ref name=":4" />
Створення записів та вилучення елементів запису завжди вимагає явної вказівки імені запису:<ref name=":4" />
<syntaxhighlight lang="erlang" line="1">
R0 = #user{}, % всі поля отримують значення за замовчуванням
R1 = #user{login = "user1", email = "user@mail.com", password = "secret"}, % Задаємо значення для всіх полів
</syntaxhighlight>
 
В оболонці можна викликати BREAK-меню за допомогою {{Клавіша|Ctrl|C}} (у Unix-подібних ОС) або {{Клавіша|Ctrl|Break}} (у Windows). Це меню має різні команди, у тому числі {{Клавіша|a}}&nbsp;— негайна зупинка, {{Клавіша|c}}&nbsp;— продовження роботи в оболонці та інші інформаційні та допоміжні команди для роботи з Erlang-системою. Комбінація клавіш {{Клавіша|Ctrl|G}} викликає ще командне меню, яким можна, за необхідності, зупинити процес, що «завісив» оболонку, і повернутися в оболонку ({{Клавіша|i}} і потім {{Клавіша|c}})<ref name=":3">{{Cite book
Оновлення одного значення в наявному записі: <code>R2 = R1#user{login = "user2"},</code>
|title=Learn You Some Erlang for Great Good!: A Beginner's Guide
|last=Hébert
|first=Fred
|year=2013
|publisher=No Starch Press
|pages=624
|language=англійська
|isbn=ISBN 978-1593274351.
}}</ref>
 
== Erlang та інші мови програмування ==
оновлення двох значень в наявному записі: <code>R2 = R1#user{login = "user2", email = "neo@matrix.org"},</code>
 
=== Інтеграція та гібридні мови ===
отримати значення по ключу з запису <code>Nick2 = R2#user.nick.</code>.
Erlang-система дозволяє виконувати інтеграцію з системами на інших мовах програмування. Є механізми для мережевої взаємодії з [[C (мова програмування)|С]], [[Java]], [[Lisp|Лісп]], [[Perl]], [[Python]], [[Ruby]]. До прикладу, для ефективнішого синхронного виклику невеликих функцій на C можна використовувати платформно-залежні функції ({{Lang-en|NIF, natively implemented function}}). Високорівневі бібліотеки дозволяють Erlang-системі представляти C або Java-вузли як звичайні Erlang-вузли. Інші мови можна пов'язати з середовищем виконання Erlang за допомогою [[драйвер]]ів або мережевих [[Сокет (програмний інтерфейс)|сокетів]] за допомогою протоколів на кшталт [[HTTP]], [[SNMP]], IIOP. До прикладу, Ruby взаємодіє з Erlang за допомогою пакета erlectricity, а для Python розроблена реалізація Erlang-вузла у вигляді пакету py-interface.<ref name=":7">{{Cite book
 
==== Карта ====
[[Карта|Асоціативний масив (словник)]] (en: map) зберігає пари виду «(ключ, значення)». І ключем, і значенням може бути будь-який терм Erlang.<ref>{{Cite web|url=http://www.erlang.org/doc/reference_manual/data_types.html|title=Data Types, Erlang Reference Manual User's Guide Version 5.10.3|date=2013|website=http://www.erlang.org/doc/reference_manual/data_types.html|publisher=Ericsson AB|language=англійська}}</ref>
<syntaxhighlight lang="erlang" line="1">
Map = #{a => 2, b => 3, c=> 4, "a" => 1, "b" => 2, "hi" => 42},
Key = "hi",
maps:find(Key,Map).
{ok,42}
</syntaxhighlight>
 
==== Інші типи ====
У мові Erlang є інші типи даних. Тип ''посилання'' ({{Lang-en|reference}}) є унікальним у межах вузла/кластера з'єднаних вузлів в середовищі часу виконання Erlang. Посилання створюється викликом функції <code>make_ref/0</code> і може повторитися через 2<sup>82</sup> викликів цієї функції. Посилання можна порівнювати на рівність, а застосовуються вони для одноразових позначок або «[[Magic cookie|чарівного печива]]»<ref name=":4" />
 
''Ідентифікатор порту'' ({{Lang-en|port identifier}}) визначає порт для зв'язку із зовнішнім по відношенню до Erlang-системи світом. Порт дозволяє процесу, що його створив-власнику (так званому приєднаному процесу) обмінюватися бінарними повідомленнями зі сторонніми програмами і ОС способом, прийнятим в даній операційній системі.<ref name=":4" /><ref>{{Cite web|url=http://www.erlang.org/doc/reference_manual/ports.html|title=Ports and Port Drivers, Reference Manual User's Guide Version 5.10.3|date=2013|website=https://web.archive.org/web/20131203022736/http://www.erlang.org/doc/reference_manual/ports.html|publisher=Ericsson AB|language=англійська|accessdate=2022-08-16|archive-date=2013-12-03|archive-url=https://web.archive.org/web/20131203022736/http://www.erlang.org/doc/reference_manual/ports.html}}</ref>
 
''Ідентифікатор процесу'' ({{Lang-en|Pid}}), як і випливає з його назви, ідентифікує процес, що породжується різними функціями <code>spawn</code>. Ідентифікатор можна вважати унікальним під час роботи Erlang-системи, але в системах, що довго працюють, можуть все-таки бути використані повторно, що зазвичай не є проблемою на практиці.<ref name=":4" />
 
==== Вбудовані функції для роботи з типами ====
Для перетворення типів використовуються вбудовані функції (BIF,{{Lang-en|builtin function}}) виду x_to_y («з x в y»), а для перевірки належності значення того чи іншого типу&nbsp;— функції виду is_x («є_x»):
<syntaxhighlight lang="erlang" line="1">
1> atom_to_list(hello).
"hello"
2> list_to_binary("world").
<<"world">>
3> tuple_to_list({1,2,3,4}).
[1,2,3,4]
1> is_integer(3).
true
2> is_tuple("abc").
false
3> is_integer(3.0).
false
</syntaxhighlight>
 
== Операції ==
 
=== Арифметичні операції ===
Erlang надає найбільш поширені арифметичні операції для цілих чисел і [[Число з рухомою комою|чисел з плаваючою комою]]:
{| class="wikitable"
!Позначення
!Операція, що виконується
!приклад
!Результат прикладу
|-
|<code>+</code>
|Унарний плюс
|<code>+3</code>
|<code>3</code>
|-
|<code>-</code>
|Унарний мінус
|<code>-3</code>
|<code>-3</code>
|-
|<code>+</code>
|Додавання
|<code>2+3</code>
|<code>5</code>
|-
|<code>-</code>
|Віднімання
|<code>7-3</code>
|<code>4</code>
|-
|<code>*</code>
|множення
|<code>1.2*0.4</code>
|<code>0.48</code>
|-
|<code>/</code>
|Ділення
|<code>5 / 3</code>
|<code>1.6666666666666667</code>
|-
|<code>div</code>
|Цілочисельне [[ділення]]
|<code>5 div 3</code>
|<code>1</code>
|-
|<code>rem</code>
|Залишок від [[Ділення з остачею|ділення]]
|<code>5 rem 3</code>
|<code>2</code>
|}
Всі ці операції [[Асоціативність (програмування)|лівоасоціативні]]. Унарні операції мають найвищий пріоритет, потім слідує множення і ділення, найменший пріоритет у складання та віднімання. При необхідності ціле може приводитися до типу з рухомою комою.<ref name=":1" />
 
=== Бітові операції ===
[[Бітові операції]] працюють над цілими числами і дають в результаті [[Цілі числа|ціле число]].<ref name=":1" />
{| class="wikitable"
!Позначення
!Операція, що виконується
!приклад
!Результат прикладу
|-
|<code>bnot</code>
|[[Бітові операції|Побітове заперечення]]
|<code>bnot (2#1000)</code>
|<code>-9</code>
|-
|<code>band</code>
|[[Бітові операції|Побітове І]]
|<code>2 band 3</code>
|<code>2</code>
|-
|<code>bor</code>
|[[Бітові операції|Побітове АБО]]
|<code>1 bor 2</code>
|<code>3</code>
|-
|<code>bxor</code>
|Побітове [[Виключна диз'юнкція|виключне АБО]]
|<code>5 bxor 3</code>
|<code>6</code>
|-
|<code>bsr</code>
|[[Бітовий зсув|Побітовий зсув]] вправо
|<code>32 bsr 2</code>
|<code>8</code>
|-
|<code>bsl</code>
|[[Бітовий зсув|Побітовий зсув]] вліво
|<code>1 bsl 5</code>
|<code>32</code>
|}
 
=== Логічні операції ===
[[Логічний сполучник|Логічні операції]] працюють над логічними значеннями <code>true</code> (істинне) і <code>false</code> (хибне), одержуваними в результаті порівнянь та застосування функцій перевірки типу:<ref name=":1" />
{| class="wikitable"
!Позначення
!Операція, що виконується
!приклад
!Результат прикладу
|-
|<code>not</code>
|[[Заперечення]] (НЕ)
|<code>not true</code>
|<code>false</code>
|-
|<code>and</code>
|[[Кон'юнкція]] (І)
|<code>true and (1 < 5)</code>
|<code>true</code>
|-
|<code>andalso</code>
|Аналогічно <code>and</code>, але не обчислює другий операнд, якщо перший <code>false</code>
|<code>false andalso (1 < 5)</code>
|<code>false</code>
|-
|<code>or</code>
|[[Диз'юнкція (логіка)|Диз'юнкція]] (АБО)
|<code>is_atom("1") or is_atom(1)</code>
|<code>false</code>
|-
|<code>orelse</code>
|Аналогічно <code>or</code> але не обчислює другий операнд, якщо перший <code>true</code>
|<code>true orelse (1 < 5)</code>
|<code>true</code>
|-
|<code>xor</code>
|[[Виключна диз'юнкція|Виключне АБО]]
|<code>true xor true</code>
|<code>false</code>
|}
 
=== Операції порівняння ===
Операції порівняння отримують два операнди, а результатом операції є логічне значення <code>true</code> або <code>false</code>. У Erlang є наступні операції: <code>==</code> (рівно), <code>=:=</code> (рівно, враховуючи тип&nbsp;— використовується для порівняння чисел), <code>/=</code> (не рівно), <code>=/=</code> (не рівно, враховуючи тип&nbsp;— використовується для порівняння чисел), <code>=<</code> (менше або дорівнює), <code><</code> (менше), <code>></code> (більше), <code>>=</code> (більше або дорівнює):
 
<code>==</code> перевірка на рівність (не враховуючи тип):
<syntaxhighlight lang="erlang" line="1">
1> 5 == 5.
true
2> 5 == 5.0.
true
</syntaxhighlight>
 
<code>=:=</code> перевірка на рівність (враховуючи тип):
<syntaxhighlight lang="erlang" line="1">
4> 5 =:= 5.
true
5> 5 =:= 5.0.
false
</syntaxhighlight>
 
Можна порівнювати значення різних типів, але вони вважаються в Erlang впорядкованими наступним чином:<ref name=":1" />
число < атом < посилання < функція < порт < ідентифікатор процесу < кортеж < список < бінарні дані
 
Списки вважаються впорядкованими в [[Лексикографічний порядок|лексикографічному порядку]], а кортежі порівнюються за довжиною, і лише потім у лексикографічному порядку.<ref name=":1" />
 
=== Змінні ===
Змінні служать для зберігання значень простих і складових типів. Ім'я змінної починається з великої літери (у спеціальних випадках&nbsp;— з підкреслення) і може містити букви, цифри, підкреслення. Змінній можна присвоїти значення лише один раз&nbsp;— ця властивість мови програмування називається одиничним присвоєнням ({{Lang-en|single assignment}}). До переваг одиничного присвоєння можна віднести усунення необхідності в блокуваннях, а також спрощення налагодження програми<ref name=":7">{{Cite book
|title=Building Web Applications with Erlang
|last=Kessin
Рядок 561 ⟶ 185:
|isbn=ISBN 978-1-4493-0996-1.
}}</ref>
 
Відбувається обчислення([[Редукція (паралельне програмування)|редукція]]) аргументів функції перед застосуванням функції до цих аргументів (вхідних параметрів).
 
[[Область видимості (програмування)|Область видимості]] змінної поширюється від її визначення (en: bind&nbsp;— зв'язування) до закінчення клози функції. Приклад:
<syntaxhighlight lang="erlang" line="1">
binomial(X) ->
Y = X * X,
X + Y.
 
prod([1|T]) -> prod(T);
prod([Y|T]) -> Y * prod(T);
prod([]) -> 1.
</syntaxhighlight>
У цьому прикладі область видимості <code>X</code>&nbsp;— весь опис функції <code>binomial/1</code>, а <code>Y</code>&nbsp;— від присвоєння до кінця опису. Змінна <code>Y</code> у другій клозі функції <code>prod/1</code> не має відношення до змінної <code>Y</code> з <code>binomial/1</code>: її область видимості поширюється до кінця цієї клози.<ref name=":1" />
 
При виході обчислень за межі області видимості змінної, пам'ять, зайнята її вмістом, може бути звільнена у процесі [[збирання сміття]], якщо значення змінної не використовується в іншій частині програми.<ref name=":4" />
 
=== [[Зіставляння зі взірцем|Зіставлення зі взірцем]] ===
[[Зіставляння зі взірцем|Зіставлення зі зразком]] (en: Pattern Matching) використовується в Erlang для [[Оператор присвоювання|присвоєння]] (у тому числі, при роботі з параметрами функцій), управління потоком виконання програми, отримання значень складових типів, вибору повідомлення з черги. У лівій частині порівняння (або в заголовку функції) можуть бути пов'язані (вже мають значення) і незв'язані (отримуючі значення) змінні, а також літерали (атоми, числа, рядки). В результаті виконання порівняння може виявитися успішним (у цьому випадку змінні зв'язуються зі значеннями) та неуспішним&nbsp;— змінні залишаються непов'язаними. У зразку можуть бути змінні, значення яких для зразка байдуже: їх імена записуються з підкреслення. Змінні, ім'я яких починається з підкреслення, це звичайні змінні, крім того, що компілятор не буде скаржитися, якщо вони не використані. Не можна прив'язувати до них значення більше одного разу.<ref name=":1" />
 
== Функції ==
Програми Erlang складаються з функцій, які викликають одне одного. Кількість вхідних аргументів (параметрів) функції називається '''''арністю'''''. При виклику функції заголовки функції зіставляються зі зразком. У разі збігу параметрів виклику формальні параметри зв'язуються з фактичними і виконується відповідна частина тіла функції. Запис варіанту обчислення функції для деякого зразка може називатися ''клозом'' від {{Lang-en|clause}}, а визначення функції&nbsp;— це набір з одного або більше клозів.
 
Для уточнення зіставлення зі зразком у функціях можна використовувати [[Варта (програмування)|охоронні вирази]], які випливають після ключового слова <code>when</code><ref name=":2" />. У прикладі нижче визначено функцію обчислення [[Signum-функція|знака числа]], яка розраховується в залежності від порівняння параметра з нулем:<syntaxhighlight lang="erlang" line="1">
sign(X) when X > 0 -> 1;
sign(X) when X == 0 -> 0;
sign(X) when X < 0 -> -1.
</syntaxhighlight>Erlang перебирає (матчить) клози функції в тому порядку, в якому вони записані (зверху вниз, зліва направо), доки не буде знайдено відповідний вираз (заголовок клози), який зматчиться.<ref name=":2" /> В охоронних виразах можна використовувати лише обмежений набір вбудованих функцій, оскільки ці функції не повинні мати [[Побічний ефект (програмування)|побічних ефектів]].
 
Функції Erlang підтримують [[Рекурсія|рекурсивні]] виклики. У разі коли визначення функції закінчується рекурсивним викликом ([[хвостова рекурсія]]), Erlang використовує оптимізацію: стек викликів не застосовується.<ref name=":2" />
 
Як параметром, і результатом функції може бути інша функція. У наступному прикладі функція одного аргументу повертає функцію додавання аргументу<ref name=":1" /><syntaxhighlight lang="erlang" line="1">
1> Plus = fun(X) -> fun(Y) -> X + Y end end. % Визначення функції, яка повертає функцію
#Fun<erl_eval.6.82930912>
2> Plus(2). % Функція повертає Fun-об'єкт
#Fun<erl_eval.6.82930912>
3> Plus(2)(3). % Такий синтаксис не працює
* 1 : syntax error before : '('
4> ( Plus(2) )(3). % Додаткові дужки дозволяють досягти необхідного результату
5
5> Plus2 = Plus(2), Plus2(3). % Те саме з використанням додаткової змінної
5
 
</syntaxhighlight>
 
=== Умовні вирази ===
Окрім матчингу та охоронних виразів у клозах функції, в Erlang є інші умовні вирази вибору: if та case. Вираз вибору дозволяє організувати зіставлення зі зразком усередині функції і зазвичай має наступний синтаксис:<syntaxhighlight lang="erlang" line="1">
if
охорона1 -> вираз11, вираз12, ... ;
охорона2 -> вираз21, вираз22, ... ;
...
охоронаN -> виразN1, виразN2, ...
end
</syntaxhighlight>Тут <code>охорона1</code>— охоронний вираз (en: guards).<ref>{{Cite web|title=Syntax in functions {{!}} Learn You Some Erlang for Great Good!|url=https://learnyousomeerlang.com/syntax-in-functions#guards-guards|website=learnyousomeerlang.com|accessdate=2022-09-10}}</ref> Охоронні вирази&nbsp;— розширення зіставлення зі зразком, що додає виразності. Без охоронних виразів ми не можемо визначати такі речі, як діапазон значень чи певні типи даних. У Erlang if&nbsp;— це вираз, який може мати декілька гілок. Гілки скануються послідовно, зверху донизу, допоки захисна послідовність не буде оцінена як true. Якщо охорона1 (перший guard в даному прикладі) поверне true одразу почнеться виконання відповідних виразів: вираз11, вираз12,… Після виконання цих виразів відбудеться вихід з блоку і наступні умови <code>охорона2, …, охоронаN</code> перевірятися не будуть. Якщо ж <code>охорона1</code> поверне <code>false</code>, відбувається перехід до перевірки наступного охоронного виразу, і так доти, поки guard не поверне значення true, після чого будуть виконані відповідні, розділені комами вирази і вихід з блоку. Слід зауважити, що і тут в охоронному виразі можна застосовувати лише обмежений набір операцій та вбудованих функцій. Коми в охоронному вираженні працюють як операція andalso, крапка з комою — як orelse, наприклад:<ref name=":2" /><syntaxhighlight lang="erlang" line="1">
if
X =< 0 -> io:format("менше або дорівнює нулю ~n", []), <<"менше або дорівнює нулю"/utf8>>;
X > 0, X < 10 -> io:format("більше нуля та менше десяти ~n", []), <<"більше нуля та менше десяти"/utf8>>;
X == 10; X == 11 -> io:format("дорівнює десяти або одинадцяти~n", []), <<"дорівнює десяти або одинадцяти"/utf8>>;
true -> io:format("більше або дорівнює дванадцяти~n", []), <<"більше або дорівнює дванадцяти"/utf8>>
end.
</syntaxhighlight>Якщо жодна захисна послідовність не є істинною, виникає помилка виконання <code>if_clause</code>. При необхідності можна використовувати захисник <code>true</code>. В останній гілці, оскільки ця захисна послідовність завжди вірна, і вважається аналогом «інше».<ref name=":9">{{Cite web|url=https://www.erlang.org/doc/|title=Erlang/OTP 25.0.4|website=https://www.erlang.org/doc/|language=Англійська|accessdate=25 серпня 2022}}</ref> Компілятор Erlang стежить за безпекою зв'язування змінних усередині умовних виразів, це ми можемо побачити на наступному прикладі:<syntaxhighlight lang="erlang" line="1">
-module(badexample).
-export([broken_if/1]).
 
broken_if(X) ->
if
X < 0 -> Z = -1;
X >= 0 -> Y = 1
end,
Y * Z.
 
</syntaxhighlight>При спробі [[Компіляція (програмування)|скомпілювати]] модуль виникають повідомлення про помилки, тому що в такому коді змінні не пов'язуються зі значенням в іншій клозі відповідно:<syntaxhighlight lang="erlang" line="1">
1> c(badexample).
badexample.erl:8: variable 'Y' unsafe in 'if' (line 4)
badexample.erl:8: variable 'Z' unsafe in 'if' (line 4)
error
</syntaxhighlight>Правильним було б визначити всі використовувані далі за кодом змінні у всіх гілках if-вирази.<ref name=":2" /><syntaxhighlight lang="erlang" line="1">
-module(if_else).
-export([compare/2, ascii/1, run/3]).
 
compare(X, Y) ->
Result = if
X > Y -> greater;
X =:= Y -> equal;
X < Y -> less
end,
io:format(" ~p is ~p than ~p ~n", [X, Result, Y]).
ascii(Letter) ->
Code = if
Letter =:= 'A' -> 101;
Letter =:= 'B' -> 102;
true -> unknown
end,
io:format(" ~p = ~p ~n", [Letter, Code]).
run(X, Y, Letter) ->
compare(X, Y),
ascii(Letter).
</syntaxhighlight>
 
Можна використовувати вираз <code>case ... of</code> для порівняння послідовності патернів. На відміну від виразу <code>if, case ... of</code> дозволяє використовувати охоронні вирази в пунктах співставлення. Якщо жодний вираз case не відповідає зразку (не матчиться), система виконання викличе помилку про відсутність відповідності: «no case clause matching». Використовувати шаблон підкреслення <code>_</code> можна, щоб захопити будь-яке інше значення, яким не відповідали попередні ключі.<ref name=":8" /><syntaxhighlight lang="erlang" line="1">
case expression of
pattern1 [when guard1] -> expr_seq1;
pattern2 [when guard2] -> expr_seq2;
...
end.
</syntaxhighlight>Спочатку обчислюється expression, припустимо, що при цьому воно набуває значення Value. Далі Value співставляється з pattern1 (разом з опціональним контролером guard1), pattern2 і так далі, до першого успішного співставлення. Як тільки це станеться, виконується послідовність виразів (expr_seqN) і результат цього обчислення стає результатом всього даного виразу. Якщо жоден із патернів не підійде, то відбувається виняткова ситуація.<ref name=":9" /><syntaxhighlight lang="erlang" line="1">
-module(case_of).
-compile([export_all, nowarn_export_all]).
admit(Person) ->
case Person of
{male, Age} when Age > 21 -> yes_with_cover;
{female, Age} when Age > 21 -> yes_no_cover;
{male, _} -> no_boy_admission;
{female, _} -> no_girl_admission;
_ -> unknown
end.
run(Person) ->
Record = admit(Person),
io:format(" ~p~n", [Record]).
</syntaxhighlight>
 
==== Приклади ====
В функціональних мовах програмування відсутні цикли, натомість використовується [[Рекурсія (програмування)|рекурсія]].
 
Розглянемо функції обчислення [[факторіал]]у:<syntaxhighlight lang="erlang" line="1">
-module(fact).
-export([fac/1, func/1]).
 
fac(0) -> 1;
fac(N) when N > 0 ->
N * fac(N-1).
</syntaxhighlight>Це рекурсія без хвостової оптимізації, вона добре працює для невеликої глибини рекурсії. Проте, стає проблематичною у випадку великої глибини рекурсії.
 
Чим більше операцій рекурсії&nbsp;— тим більше займе пам'яті дана програма у стеку при виконанні, дана рекурсія розгортається у стек&nbsp;— відповідно, чим більше рекурсивних викликів&nbsp;— тим більше пам'яті займе дана програма при виконанні.<ref name=":9" />
 
Хвостова рекурсія&nbsp;— це рекурсія, яка викликається останньою інструкцією, таким чином стек залишається незмінним (або ж практично незмінним) і функція може працювати перманентно без зупинки.<ref name=":9" /><syntaxhighlight lang="erlang" line="1">
func(N) -> func(N,1).
func(0,A) -> A;
func(N,A) when N > 0 -> func(N-1, N*A).
</syntaxhighlight>Хвостова рекурсія незалежна від кількості рекурсивних викликів&nbsp;— в пам'яті залишаються лише два числа.
 
Спробуємо написати функцію обчислення N-ного [[Послідовність Фібоначчі|числа Фібоначчі]] на Erlang двома шляхами-алгоритмами. Спочатку звичайна рекурсія.<syntaxhighlight lang="erlang" line="1">
-module(fibonacci).
-export([fib_usual/1, fib_tail/1]).
 
fib_usual(1) -> 0;
fib_usual(2) -> 1;
fib_usual(N) when N > 0 ->
fib_usual(N - 1) + fib_usual(N - 2).
</syntaxhighlight>Дана функція тримає всі числа-проміжні результати одночасно у памяті, і кількість рекурсивних викликів функції&nbsp;— активних процесів&nbsp;— зростає надто стрімко.
 
Хвостова рекурсія в даному випадку пишеться з використанням двох тимчасових змінних в якості параметрів нашої функції. Такі змінні називаються акумуляторами та використовуються для зберігання проміжних результатів наших обчислень, щоб не зберігати багато незакінчених обчислень (процесів, які очікують результат розрахунків від інших процесів) у пам'яті.<syntaxhighlight lang="erlang" line="1">
fib_tail(N) when is_integer(N), N > 0 ->
fib_tail(N, 1, 0).
fib_tail(0, A1, _) -> A1;
fib_tail(N, A1, A2) ->
fib_tail(N - 1, A2, A1 + A2).
</syntaxhighlight>
 
У памяті тримаються лише три числа та займається обчисленнями лише один процес.
 
Додамо декілька функцій, які працюють рекурсивно зі списком і виконують такі звичні для всіх нас завдання:
 
- визначення довжини масиву;
 
- знаходження максимального (мінімального) елемента масиву;
 
- обчислення суми всіх елементів масиву.
 
1. Визначення довжини масиву:
 
- спочатку звичайна рекурсія <syntaxhighlight lang="erlang" line="1">
len_list([]) -> 0;
len_list([_]) -> 1;
len_list([_H|T]) when is_list([_H|T]) ->
1 + len_list(T).
</syntaxhighlight>- хвостова рекурсія з акумулятором<syntaxhighlight lang="erlang" line="1">
length_tail(List) when is_list(List)->
length_tail(List, 0).
length_tail([], Acc) -> Acc;
length_tail([_|Tail], Acc) ->
length_tail(Tail, 1 + Acc).
</syntaxhighlight>
 
2. Знаходимо максимальний елемент масиву:
 
- спочатку звичайна рекурсія<syntaxhighlight lang="erlang" line="1">
max_el([Last]) when is_number(Last) -> Last;
 
max_el([H | T]) when hd(T) >= H ->
max_el(T);
max_el([H | T]) ->
max_el([H | tl(T)]).
</syntaxhighlight>
 
- та сама функція, з допомогою хвостової рекурсії і акумулятора<syntaxhighlight lang="erlang" line="1">
tail_maxx([H | T]) when is_number(H)->
tail_maxx(T, H).
tail_maxx([], Acc) when is_number(Acc) ->
Acc;
tail_maxx([H | T], Acc) when H >= Acc ->
tail_maxx(T, H);
tail_maxx([_ | T], Acc) ->
tail_maxx(T, Acc).
</syntaxhighlight>
 
3. Підрахуємо суму елементів масиву:
 
- звичайна рекурсія<syntaxhighlight lang="erlang" line="1">
sumx([]) -> 0;
sumx([H | T]) -> H + sumx(T).
</syntaxhighlight>
 
- підрахунок суми елементів масиву з допомогою хвостової рекурсії<syntaxhighlight lang="erlang" line="1">
tail_sum(List) -> tail_sum(List, 0).
 
tail_sum([], Acc) -> Acc;
tail_sum([H | T], Acc) -> tail_sum(T, Acc + H).
</syntaxhighlight>
 
Один з алгоритмів сортування&nbsp;— [[швидке сортування]]<ref name=":5" /><syntaxhighlight line="1" lang="erlang">
-module(qsort).
-export([qsort/1]).
 
qsort([]) -> [];
qsort([Pivot|Rest]) ->
qsort([Front || Front <- Rest, Front < Pivot]) ++ [Pivot] ++
qsort([Back || Back <- Rest, Back >= Pivot]).
</syntaxhighlight>
 
У цьому прикладі функція <code>qsort</code> викликається рекурсивно до вичерпання всіх елементів. Вираз <code>[Front || Front <- Rest, Front < Pivot]</code> збирає список <code>Front</code> з елементів <code>Rest</code> таких, що елемент <code>Front</code> менший за <code>Pivot</code>. Оператор <code>++</code> [[Конкатенація|склеює]] списки.
 
=== Препроцесор та макроси ===
[[Препроцесор]] Erlang (EPP) дозволяє вкладати файли з вихідним кодом один в інший, визначати [[Макрокоманда|макроси]] та здійснювати прості та параметризовані макропідстановки.<ref name=":1" /> Макрос визначається за допомогою директиви <code>-define</code>, а макропідстановка здійснюється вказівкою імені макроса та можливих параметрів після знака питання (<code>?</code>). Наступний приклад показує визначення та застосування параметризованого макроса:<syntaxhighlight lang="erlang" line="1">
-define(ZERO(X), X == 0).
 
is_zero(T) when ?ZERO(X) -> true;
is_zero(T) -> false.
</syntaxhighlight>Ім'я макроса зазвичай пишеться великими літерами. Визначення макроса має містити [[Лексичний аналіз|лексеми]] Erlang цілком (наприклад, спроба задати частину імені змінної за допомогою макроса викликає синтаксичну помилку). Макроси можуть використовуватися для підвищення [[Прочитність|зручності читання]] коду в охоронних виразах, для операторів налагодження і&nbsp;т.&nbsp;ін. Препроцесор має декілька визначених макросів, які не можна перевизначити: <code>?MODULE</code>, <code>?MODULE_STRING</code>, <code>?FILE</code>, <code>?LINE</code>, <code>?MACHINE</code>.<ref>{{Cite book
|title=The Preprocessor, Predefined Macros, Erlang Reference Manual User's Guide Version 5.10.3
|year=2013
|publisher=Ericsson AB
|language=англійська
}}</ref>
 
Заголовний файл (розширення <code>.hrl</code>) з визначеннями макросів та записів можна включити за допомогою директиви <code>-include</code>.<ref name=":1" />
 
=== Обробка помилок ===
Для обробки [[Обробка винятків|виняткових ситуацій]] Erlang можна застосовувати конструкцію <code>try ... catch</code>, в загальному випадку записується в наступному вигляді<ref name=":1" /><syntaxhighlight lang="erlang" line="1">
try вираз для обчислення of
зразок1 when охорона1 -> вираз1;
зразок2 when охорона2 -> вираз2;
...
зразокN when охоронаN -> виразN
catch
класс1:зразокВикл1 when охоронаВикл1 -> виразВикл1;
...
классМ:зразокВиклМ:Stacktrace when охоронаВиклМ -> виразВиклМ;
end
</syntaxhighlight>Як і у випадку case-виразу, вираз, що обчислюється, зіставляється зі зразком (частини між <code>of</code> і <code>catch</code>) для отримання результату.<ref name=":2" /> Після ключового слова <code>catch</code> слідують частини обробки винятків, у яких на додаток до зразків винятків можуть бути вказані класи винятків (перед двокрапкою): <code>error</code>, <code>throw</code> та <code>exit</code>. Stacktrace — це список викликів функцій, обчислення яких виконувала програма, коли було створено виняток. Підкреслення може використовуватись як у зразку, так і в класі виключення. Наступний простий приклад ілюструє перехоплення помилки класу <code>error</code> при обчисленні [[Квадратний корінь|квадратного кореня]].<syntaxhighlight lang="erlang" line="1">
1> try math:sqrt(-1) catch error:Error -> {error, Error} end.
{error, badarith}
2> try math:sqrt(4) catch error:Error -> {error, Error} end.
2.0
</syntaxhighlight>Для створення винятків, визначених користувачем, використовується функція <code>throw/1</code>, яка приймає кортеж з більш детальним описом помилки,<ref name=":2" /> що виникла і генерує виняток класу <code>throw</code>. Використання цієї функції небажане через погіршення зручності читання коду програми, але може знадобитися в деяких випадках при роботі з вкладеними структурами даних, наприклад, при розборі [[XML]]<ref name=":1" />. Винятки класу <code>exit</code> виникають у результаті виклику вбудованої функції <code>exit/1</code> або сигналу виходу.
 
До розробки Річардом Карлссоном (Richard Carlsson) з команди проєкту HiPE описаного вище нового механізму обробки винятків (з'явився у версії R10B) в Erlang використовувалися catch-вирази.<ref name=":1" />
 
== Модулі ==
Код програми на Erlang можна розбити на окремі [[Модульне програмування|модулі]]. Модуль&nbsp;— це ім'я для набору функцій, організованих в одному файлі. Ім'я модуля має збігатися з ім'ям файлу (якщо відкинути [[Розширення назви файлу|розширення]])<ref name=":1" />. Модуль можна відкомпілювати в байт-код як із командного рядка операційної системи, так і з командної оболонки Erlang<ref name=":3" />. У файлі модуля можна записати оголошення функцій та '''''директиви''''' (іноді називаються атрибутами). Обов'язковим атрибутом є лише <code>-module(атом_імені_модуля).</code> Інший атрибут, що часто використовується&nbsp;— <code>-export</code>&nbsp;— застосовується для опису списку експортованих функцій, тобто функцій, які можна використовувати за межами модуля.
 
Функції в Erlang однозначно визначаються модулем, ім'ям та [[Арність|арністю]]. Наприклад, <code>math:cos/1</code> відповідає функції <code>cos</code> з модуля <code>math</code> приймає один аргумент. Викликати функцію можна так: <code>math:cos(1.2)</code><ref name=":1" />
 
[[Початковий код|Вихідний текст]] модуля компілюється в BEAM-файл&nbsp;— файл, що містить байт-код віртуальної машини '''''BEAM''''' ({{Lang-en|Bogdan’s/Björn's Erlang Abstract Machine}}<span lang="en" style="font-style:italic;">Bogdan's/Björn's Erlang Abstract Machine</span>{{sfn|Hebert|2013|місце=Modules}}). У свою чергу, '''''ERTS''''' ({{Lang-en|Erlang Runtime System}}<span lang="en" style="font-style:italic;">Erlang Runtime System</span>&nbsp;— система часу виконання Erlang) виконує цей код.<ref name=":2" />
 
=== Процеси ===
Основною абстракцією [[Паралельний алгоритм|паралельного програмування]] в Erlang є ''процес''. Процеси можуть породжувати інші процеси, виконуватися одночасно, обмінюватися повідомленнями, реагувати на завершення один одного.
 
=== Створення процесів ===
Erlang має невеликий, але потужний набір примітивів для створення процесів і спілкування між ними.
 
Міжпроцесовий зв'язок працює за допомогою асинхронної системи передачі повідомлень, яка не має спільного доступу: кожен процес має «поштову скриньку»&nbsp;— чергу повідомлень, які були надіслані іншими процесами та ще не використані. Для отримання повідомлень, які відповідають бажаним паттернам, процес використовує примітив <code>receive</code>. Процедура обробки повідомлень перевіряє повідомлення по черзі на відповідність кожному паттерну, поки один з них не збігається. Коли повідомлення використано та видалено з поштової скриньки, процес відновлює виконання. Повідомлення може містити будь-яку структуру Erlang, включаючи примітиви (цілі числа, числа з плаваючою точкою, символи, атоми), кортежі, списки та функції.
 
Для створення нового процесу служить декілька вбудованих функцій (<code>spawn</code> та її аналоги){{sfn|Martin Logan, et al|2011|с=75}}. Функції повертають ідентифікатор процесу, який може використовуватися, наприклад, для надсилання повідомлень новоствореному процесу. В інтерактивній консолі erl можна отримати список процесів та іншу інформацію за допомогою функцій <code>processes().</code> та <code>i().</code> відповідно.<ref name=":1" />
 
Наведений нижче приклад коду показує вбудовану підтримку розподілених процесів:
<syntaxhighlight lang="erlang" line="1">
%% Створимо процес та викличемо функцію web:start_server(Port, MaxConnections)
ServerProcess = spawn(web, start_server, [Port, MaxConnections]),
 
%% Створимо віддалений процес та викличемо функцію
%% web:start_server(Port, MaxConnections) на віддаленій ноді RemoteNode
RemoteProcess = spawn(RemoteNode, web, start_server, [Port, MaxConnections]),
 
%% Відправимо повідомлення процесу ServerProcess (асинхронно).
%% Повідомлення складається з кортежа з атомом "pause" та числом "10".
ServerProcess ! {pause, 10},
 
%% Отримаємо повідомлення, надіслані цьому процесу
receive
a_message -> do_something;
{data, DataContent} -> handle(DataContent);
{hello, Text} -> io:format("Got hello message: ~s", [Text]);
{goodbye, Text} -> io:format("Got goodbye message: ~s", [Text])
end.
</syntaxhighlight>
Як показує приклад, процеси можуть бути створені у віддалених вузлах, і взаємодія з ними є прозорою у тому сенсі, що взаємодія з віддаленими процесами працює точно так само, як взаємодія з локальними процесами.
 
Розподіленість (en: Concurrency) підтримує основний метод обробки помилок в Erlang. Коли процес аварійно завершується, він акуратно завершує роботу та надсилає повідомлення керуючому процесу, який потім може вжити заходів, наприклад запустити новий процес, який бере на себе завдання старого процесу.
 
=== Передача та прийом повідомлень ===
Як і мова [[Occam]], Erlang використовує для відправки повідомлення синтаксис зі знаком оклику: <code>Process_ID ! Message</code>.
Прийом повідомлення&nbsp;— тобто вилучення його з черги («поштової скриньки») процесу&nbsp;— виконується за допомогою receive-виразів, які зазвичай записуються таким чином<ref name=":1" />:
<syntaxhighlight lang="erlang" line="1">
receive
зразок1 when охорона1 -> вираз11, вираз12, ...;
зразок2 when охорона2 -> вираз21, вираз22, ...;
...
зразокN when охоронаN -> виразN1, виразN2, ...;
Непов'язанаЗміннаДляІншихПовідомлень -> вираз1, вираз2, ...
end
</syntaxhighlight>
Зустрівши такий вираз, інтерпретатор послідовно переглядає повідомлення з черги. Кожне повідомлення інтерпретатор зіставляє зі зразком і, якщо воно відповідає зразку, то обчислюються відповідні вирази. Коли всі повідомлення перебрані, і потрібного не виявилося, процес очікує нових повідомлень, після чого перебір черги повторюється. Якщо в receive-виразі відсутній зразок, якому задовольняє будь-яке повідомлення, такий вираз називається вибірковим receive-виразом.<ref name=":1" />
 
=== Обробка помилок та завершення процесів ===
Процес можна зв'язати з іншим, у результаті між процесами встановлюється ''двонаправлене з'єднання'' ({{Lang-en|link}}). Якщо один із процесів завершується ненормально, всім пов'язаним з ним процесам передається ''сигнал виходу'' ({{Lang-en|exit signal}}). Процеси, що отримали сигнал, завершуються, поширюючи сигнал далі. Сигнал виходу є кортежем, елементами якого є атом <code>'EXIT'</code> (вихід), ідентифікатор процесу, що завершився, і причину завершення процесу. Причина завершення передається ланцюжком процесів, що завершуються.<ref name=":1" />
 
Процес може здійснити ''перехоплення помилки'' ({{Lang-en|trapping errors}}), якщо він має прапорець перехоплення виходу. Такий процес отримує сигнали виходу пов'язаних з ним процесів у вигляді звичайних повідомлень з аналогічною структурою кортежу. Перехоплений сигнал виходу більше не передається пов'язаним з процесом-перехоплювачем процесам. Сигнал виходу з причиною&nbsp;— атомом <code>normal</code> (нормальне завершення процесу) не викликає завершення пов'язаного процесу. Якщо ж причина&nbsp;— атом <code>kill</code>, процес завершується беззастережно (незалежно від прапорець перехоплення виходу), а пов'язаним з ним процесам як причина відправляється атом <code>killed</code>, що дає їм можливість зреагувати.<ref name=":1" />
 
Erlang має можливість встановити і однонаправлене з'єднання. При завершенні процесу, що спостерігається, процес-спостерігач отримує повідомлення із зазначенням причини завершення. Процес може зупинити себе сам чи зупинити інший процес, викликавши функцію <code>exit.</code><ref name=":1" />
 
=== Ввід-вивід ===
У [[Планувальник завдань|планувальнику]] процесів Erlang-системи проблема [[Ввід/вивід|вводу-виводу]], властива багатьом іншим мовам паралельного програмування, вирішена достатньо елегантно. Управління вводом-виводом, інтегроване з планувальником, вже на нижньому рівні здійснюється на основі подій, що дозволяє програмі обробляти вхідні та вихідні дані без зайвих блокувань. Такий підхід вимагає меншого числа випадків установлення та розриву з'єднань, а також прибирає необхідність блокування та [[перемикання контексту]]. Спосіб частіше застосовується в системах з явними вимогами високої доступності та низького часу відгуку. Реалізація подієво-орієнтованого вводу-виводу вбудована в Erlang-систему. Це є перевагою при проєктуванні паралельних додатків.<ref name=":4" />
 
Стандартна бібліотека містить модуль <code>io</code> з функціями вводу-виводу. Такі функції містять в собі [[Побічний ефект (програмування)|побічні ефекти]]. Вони полягають, наприклад, у появі виведеної інформації в консолі або у записуванні даних у файл на диску. Наприклад, функція <code>io:format</code> для форматованого виводу виводить рядок із підстановкою параметрів, повертаючи у разі успіху атом <code>ok.</code><ref name=":1" /><syntaxhighlight line="1" lang="erlang">
1> io:format("приклад виводу : ~p~n", [1]).
приклад виводу : 1
ok
</syntaxhighlight>Функції модуля <code>io</code> передбачають стандартний серверний [[Інтерфейс (об'єктно-орієнтоване програмування)|інтерфейс]] вводу-виводу. Протокол вводу-виводу Erlang ({{Lang-en|The Erlang I/O-protocol}}) детально визначає зв'язок клієнта і сервера, забезпечує двонаправлений зв'язок між клієнтами та серверами. Сервер вводу/виводу&nbsp;— це процес, який обробляє запити та виконує потрібне завдання, наприклад, на пристрої введення/виведення. Клієнт&nbsp;— це будь-який процес Erlang, який бажає читати або писати дані з/на пристрій введення/виведення.<ref>{{Cite web|url=https://www.erlang.org/doc/apps/stdlib/io_protocol.html|title=The Erlang I/O-protocol, STDLIB User's Guide Version 1.19.4|date=24 грудня 2013|publisher=Ericsson AB|language=англійська}}</ref>
 
== Бібліотеки ==
 
==== Стандартна бібліотека модулів ====
Згідно з офіційною документацією, стандартна бібліотека модулів STDLIB<ref name=":6" /> є обов'язковою для включення до мінімальної системи Erlang/OTP<ref name=":10">{{Cite web|url=http://www.erlang.org/doc/man/STDLIB_app.html|title=STDLIB, STDLIB Reference Manual Version 1.19.3|date=2013|publisher=Ericsson AB|accessdate=2013-12-01|language=en|archivedate=2013-11-07|archiveurl=https://web.archive.org/web/20131107140904/http://www.erlang.org/doc/man/STDLIB_app.html|deadurl=no}}</ref> разом з ядром Erlang. Бібліотека містить модулі, що надають різноманітні функції для роботи з вбудованими типами та іншими структурами даних, вводу-виводу, звернення до середовища, для роботи з файловою системою, процесами тощо.
 
Згідно з офіційною документацією, стандартна бібліотека модулів STDLIB є обов'язковою для включення до мінімальної системи Erlang/OTP<ref name=":10"/> разом з ядром Erlang. Бібліотека містить модулі, що надають різноманітні функції для роботи з вбудованими типами та іншими структурами даних, вводу-виводу, звернення до середовища, для роботи з файловою системою, процесами тощо.
 
Модуль <u><code>[https://www.erlang.org/doc/man/array array]</code></u> :
 
* визначає (функціональний) [[абстрактний тип даних]] для [[Динамічний масив|динамічного масиву.]]
* містить функції вилучення та оновлення елементів масиву, рекурсивні функції для роботи з масивами.
Модуль <u><code>[https://www.erlang.org/doc/man/string string]</code></u> розширює можливості модуля <code>[https://www.erlang.org/doc/man/lists.html#all-2 lists]</code> функціями для роботи безпосередньо зі списками символів, якими є рядки в мові Erlang.
 
Модуль <u><code>[https://www.erlang.org/doc/man/dict dict]</code></u> (від {{Lang-en|dictionary}}&nbsp;— словник) містить функції для [[Асоціативний масив|асоціативного масиву]]. Наприклад, збереження, вилучення та видалення значення за ключем, з'єднання масивів тощо.
 
Модуль <u><code>[https://www.erlang.org/doc/man/math math]</code></u> містить математичні функції.
 
Модуль <u><code>[https://www.erlang.org/doc/man/random random]</code></u> містить функції для генерації псевдовипадкових чисел.
 
Модуль <u><code>[https://www.erlang.org/doc/man/calendar calendar]</code></u> забезпечує обчислення місцевого та універсального часу, дня тижня та багатьох функцій перетворення часу. Час є місцевим, коли він налаштований відповідно до поточного часового поясу та літнього часу. Час є універсальним, коли він відображає час на нульовій довготі без будь-яких поправок на літній час.
 
Модуль <u><code>[https://www.erlang.org/doc/man/timer timer]</code></u> містить функції переведення інтервалів часу до мілісекунд, запуску подій за таймером та інші, пов'язані з часом, функції.
 
Модуль <u><code>[https://www.erlang.org/doc/man/erlang erlang]</code></u> містить вбудовані функції Erlang; по замовчуванню, функції з цього модуля є імпортованими в кожен модуль.
 
Модуль <u><code>[https://www.erlang.org/doc/man/file.html file]</code></u> забезпечує інтерфейс до файлової системи. Функції для відкриття, закриття, читання та запису файлів; перегляду директорій і&nbsp;т.&nbsp;д.
 
Модуль <u><code>[https://www.erlang.org/doc/man/filelib.html filelib]</code></u> містить утиліти вищого рівня, ніж модуль <u><code>[https://www.erlang.org/doc/man/file.html file]</code></u>. Цей модуль не підтримує «необроблені» імена файлів (тобто файли, імена яких не відповідають очікуваному кодуванню). Такі файли ігноруються функціями цього модуля. Допоміжні функції для маніпуляцій з файлами:
 
* <code>ensure_dir(Name) -> ok | {error, Reason}</code>&nbsp;— Переконується, що всі батьківські каталоги для вказаного файлу або імені каталогу існують, намагаючись створити їх, якщо необхідно. Повертає OK, якщо всі батьківські каталоги вже існують або можуть бути створені. Повертає {error, Reason}, якщо якийсь батьківський каталог не існує та не може бути створений.
* <code>ensure_path(Path) -> ok | {error, Reason}</code>&nbsp;— Переконується, що всі батьківські каталоги для вказаного шляху Path існують, намагаючись створити їх, якщо необхідно. На відміну від secure_dir/1, ця функція намагатиметься створити всі сегменти шляху як каталог, включаючи останній сегмент. Повертає OK, якщо всі батьківські каталоги вже існують або можуть бути створені. Повертає <code>{error, Reason}</code>, якщо якийсь батьківський каталог не існує та не може бути створений.
 
Модуль <u><code>[https://www.erlang.org/doc/man/filename filename]</code></u> містить функції для аналізу та обробки імен файлів. Ці функції створені таким чином, щоб код Erlang міг працювати на багатьох різних платформах із різними форматами імен файлів. Назва файлу може бути короткою відносною назвою, наприклад foo.erl, довгою абсолютною назвою, включаючи позначення диска, назвою каталогу, як-от D:\usr/local\bin\erl/lib\tools\foo.erl, або будь-якими варіаціями між ними. Допоміжні функції для маніпуляцій з файлами:
 
* <code>absname(Filename) -> file:filename_all()</code>&nbsp;— Перетворює відносне ім'я файлу та повертає абсолютне ім'я. Не робить спроб створити найкоротшу абсолютну назву, оскільки це може дати неправильні результати у файлових системах, які дозволяють посилання.
* <code>absname(Filename, Dir) -> file:filename_all()</code>&nbsp;— Те саме, що absname/1, за винятком того, що каталог, до якого має бути віднесене ім'я файлу, вказано в аргументі Dir.
 
Модуль <u><code>[https://www.erlang.org/doc/man/io.html io]</code></u> забезпечує інтерфейс до стандартних серверів введення/виведення Erlang. Усі функції виведення повертають ОК, якщо вони успішні, або завершують роботу, якщо це не так. Функції в цьому модулі мають додатковий параметр IoDevice. Якщо він включений, це буде pid процесу, який обробляє протоколи введення/виведення. Зазвичай&nbsp;— IoDevice, який повертає file: open/2. Якщо IoDevice не вказано, використовується standard_io. Опис протоколів вводу-виводу є у розділі «Протокол вводу-виводу Erlang» у посібнику користувача.
 
Модуль <u><code>[https://www.erlang.org/doc/man/io_lib io_lib]</code></u>&nbsp;— функції бібліотеки введення/виведення. Містить функції для перетворення в / і з рядків (списків символів). Вони використовуються для реалізації функцій в модулі [https://www.erlang.org/doc/man/io.html io].
 
Модуль <u><code>[https://www.erlang.org/doc/man/crypto.html crypto]</code></u> забезпечує набір криптографічних функцій. Наявні хеш-функції:
 
* SHA1, SHA2&nbsp;— Secure Hash Standard [FIPS PUB 180-4].
* SHA3&nbsp;— Standard: Permutation-Based Hash and Extendable-Output Functions [FIPS PUB 202].
* BLAKE2&nbsp;— fast secure hashing.
* MD5&nbsp;— Message Digest Algorithm [<nowiki>RFC 1321</nowiki>].
* MD4&nbsp;— Message Digest Algorithm [<nowiki>RFC 1320</nowiki>].
Модуль [https://www.erlang.org/doc/man/crypto_app <code><u>crypto_app</u></code>]&nbsp;— додаток [https://www.erlang.org/doc/man/crypto.html <u><code>crypto</code></u>]. Метою програми crypto є надання Erlang API для криптографічних функцій. API знаходиться на досить низькому рівні, і є деякі відповідні функції API, доступні в public_key(3), на вищому рівні абстракції, який використовує криптододаток у своїй реалізації. Поточна реалізація крипто використовує nifs для інтерфейсу криптобібліотеки OpenSSL і може працювати з обмеженою функціональністю зі старими версіями, як OpenSSL 0.9.8c. Підтримка режиму FIPS вимагає принаймні версії 1.0.1 і встановлення OpenSSL із підтримкою FIPS. Рекомендується використовувати версію, яка офіційно підтримується проєктом OpenSSL. API-сумісні серверні модулі, такі як LibreSSL, також повинні працювати. Криптододаток щодня тестується принаймні з однією версією OpenSSL 1.0.1, 1.0.2, 1.1.0, 1.1.1 і 3.0. Режим FIPS також перевірено для 1.0.1 і 1.0.2. Використання OpenSSL 3.0 із механізмами або в режимі FIPS ще не підтримується програмою OTP/crypto. Вихідні версії OpenSSL можна завантажити з домашньої сторінки проєкту OpenSSL або з перелічених там сайтів-дзеркал.
 
Окрім цих найбільш важливих модулів, стандартна бібліотека містить багато інших, з якими можна познайомитися за документацією.<ref name=":1" />
 
=== Таблиці ETS та DETS ===
Для організації [[Колекція (програмування)|колекцій]] в оперативній пам'яті в Erlang є модуль ETS ({{Lang-en|Erlang Term Storage}}&nbsp;— «сховище термів Erlang»). ETS може зберігати чотири види колекцій: [[Множина (тип даних)|множина]] ({{Lang-en|set}}), [[впорядкована множина]] ({{Lang-en|ordered set}}), [[мультимножина]] ({{Lang-en|bag}}), [[Множина (тип даних)|мультимножина з повтореннями]] ({{Lang-en|duplicate bag}}).<ref name=":2" /> Доступ до елементів колекцій відбувається ключовим полем кортежу(ключі, як і значення, можуть бути будь-яких типів). Упорядковані множини зреалізовані у вигляді бінарних збалансованих [[АВЛ-дерево|АВЛ-дерев]], а інші колекції&nbsp;— з використанням [[Геш-таблиця|хеш-таблиць]].<ref name=":1" />
 
DETS-таблиці доповнюють функціональність ETS-таблиць (за винятком впорядкованих множин), дозволяючи зберігати дані у файлах.
 
=== Фреймворк OTP ===
[[Файл:Дерево процесів.png|альт=|праворуч|безрамки|Дерево процесів Erlang]]
OTP ({{Lang-en|Open Telecom Platform}}) є налагодженим набором корисних поведінок ({{Lang-en|behaviours}}) процесів. Він використовується для створення серверних програм. OTP формалізує дії процесів та дозволяє будувати на їх основі [https://www.erlang.org/doc/applications.html <u>OTP-додатки</u>]. У [https://www.erlang.org/doc/man_index.html модулях ОТР] визначено загальні, стандартизовані шаблони для конструювання паралельних додатків. <u>[https://www.erlang.org/doc/man/gen_server.html <code>Gen_server</code>]</u>&nbsp;— інтерфейсний модуль для реалізації клієнт-серверної архітектури.<ref>{{Cite web|title=Erlang -- gen_server|url=https://www.erlang.org/doc/man/gen_server.html|website=www.erlang.org|accessdate=2022-09-16}}</ref> Загальний серверний процес ([https://www.erlang.org/doc/man/gen_server.html <code>gen_server</code>]), реалізований за допомогою цього модуля, має стандартний набір інтерфейсних функцій і включає функції відстеження та звітування про помилки. Він вписується в дерево нагляду OTP. Найпопулярнішими поведінками є узагальнений сервер та спостерігач ({{Lang-en|supervisor}})<ref>{{Cite web|title=Erlang -- supervisor|url=https://www.erlang.org/doc/man/supervisor.html|website=www.erlang.org|accessdate=2022-09-16}}</ref>. Є й інші поведінки: [[Скінченний автомат|кінцевий автомат]], обробник [https://www.erlang.org/doc/man/gen_event.htm подій]<ref>{{Cite web|title=Erlang -- gen_statem|url=https://www.erlang.org/doc/man/gen_statem.html|website=www.erlang.org|accessdate=2022-09-16}}</ref>.<ref name=":2" /> OTP містить і інше [[Проміжне програмне забезпечення|сполучне програмне забезпечення]] ({{Lang-en|middleware}}), наприклад, [[Система управління базами даних|СУБД]] [[Mnesia]].
 
OTP-поведінки поділяються на робочі процеси ({{Lang-en|worker processes}}):
 
* Що виконують власне обробку запитів,
* Процеси-спостерігачі ({{Lang-en|supervisors}}).
 
У завдання процесів спостерігачів входить стеження за робочими процесами та іншими процесами спостерігачами&nbsp;— нащадками. Дерева спостерігачів складають OTP-додаток ({{Lang-en|application}}). Документація Erlang визначає OTP-додаток компонентом, який реалізує деяку функціональність, яка може бути незалежно запущена на виконання і зупинена як ціле, а також [[Повторне використання коду|повторно використана]] в інших системах.<ref>{{Cite web|url=https://www.erlang.org/doc/apps/kernel/application.html|title=application, Kernel Reference Manual Version 2.16.3|date=1 листопада 2013|website=https://www.erlang.org/doc/apps/kernel/application.html|publisher=Ericsson AB|language=англійська|accessdate=2013}}</ref> Розробник програми пише код '''''модулів функцій зворотного виклику''''' ({{Lang-en|call-back module}}), в яких і знаходиться специфічна для цієї програми частина функціональності.<ref name=":1" />
 
Строго кажучи, OTP не є частиною мови Erlang. Однак, він настільки увійшов у культуру та практику розробників на Erlang, що часом між ними складно провести межу.<ref name=":2" />
 
=== Розробка графічного інтерфейсу користувача ===
Розробка додатків з [[Графічний інтерфейс користувача|графічним інтерфейсом користувача]] (крім [[Вебінтерфейс|веб-інтерфейсів]]) може вестись за допомогою бібліотеки wxErlang&nbsp;— бібліотеки [[wxWidgets]], портованої для Erlang. В стандартну поставку Erlang/OTP входить WxErlang. WxWidgets написаний на [[C++]], тому перед розробниками wxErlang стояло завдання виразити засобами Erlang ієрархію [[Об'єкт (програмування)|об'єктів]]. Спрощуючи, у wxErlang [[Клас (програмування)|класам]] відповідають модулі, а об'єктам&nbsp;— посилання, макросам на C ++ відповідають макроси Erlang. Деякі типи даних, для яких у C++ були використані класи, подаються в Erlang за допомогою інших типів даних, наприклад wxPoint задається у вигляді кортежу з двох елементів. Події wxErlang можна оброблити в Erlang або через функцію зворотнього виклику ({{Lang-en|call-back functions}}), або в більш природному середовищі Erlang передачею повідомлень.<ref name=":1" />
 
== Програмування на Erlang ==
 
=== Інтерактивна оболонка ===
[[Файл:Інтерактивна оболонка erl в окремому вікні.png|міні|333x333пкс|Інтерактивна оболонка erl в окремому вікні]]
Інтерактивна оболонка ({{Lang-en|shell}}) для Erlang може бути викликана в [[UNIX-подібні операційні системи|Unix-подібних системах]] командою <code>erl</code>, у Windows&nbsp;— <code>werl</code>.
 
Оболонка дозволяє:
 
* вводити вирази та отримувати результат їх виконання, випробувати новий код,
* займатися інтерактивним налагодженням,
* керувати системою, що знаходиться в промисловій експлуатації, тощо.<ref name=":4" />
 
Також, оболонка дозволяє використовувати додаткові функції (команди), доступні тільки в ній. До прикладу, команда <code>q().</code> здійснює вихід із оболонки із завершенням всього, що робить Erlang-система.<ref name=":4" />
 
В оболонці можна викликати BREAK-меню за допомогою {{Клавіша|Ctrl|C}} (у Unix-подібних ОС) або {{Клавіша|Ctrl|Break}} (у Windows). Це меню має різні команди, у тому числі {{Клавіша|a}}&nbsp;— негайна зупинка, {{Клавіша|c}}&nbsp;— продовження роботи в оболонці та інші інформаційні та допоміжні команди для роботи з Erlang-системою. Комбінація клавіш {{Клавіша|Ctrl|G}} викликає ще командне меню, яким можна, за необхідності, зупинити процес, що «завісив» оболонку, і повернутися в оболонку ({{Клавіша|i}} і потім {{Клавіша|c}})<ref name=":3" />
 
=== Документування та оформлення коду ===
Система EDoc може генерувати документацію з вихідного коду. Для документування коду модуля достатньо додати певним чином розмічений текст, а також файл <code>overview.edoc</code> для документації рівня проєкту (в останньому необов'язково використовувати знаки коментаря)<ref name=":2" />. Інструменти для роботи з кодом на Erlang, наприклад, erlang-режим в [[Emacs]], мають на увазі деякі особливості щодо вживання символів коментаря. Коментарем вважається текст від знака відсотка (<code>%</code>) до кінця рядка в Erlang. Так, потрійний знак відсотка викликає вирівнювання лівим краєм, подвоєний&nbsp;— вирівнювання на рівні навколишнього коду, а одиночний знак відсотка використовується для позначення коментаря після коду, в кінці рядка<ref name=":2" />. Розробники Erlang виробили певні [[Стандарт оформлення коду|стильові угоди]] щодо організації та оформлення вихідного коду. Наприклад, хорошим стилем вважається зниження вкладеності синтаксичних структур, написання коротких модулів (менше 400 рядків коду) та функцій (не довше 15-20 рядків коду), використання осмислених імен для змінних та функцій тощо.<ref>{{Cite web|url=http://erlang.se/doc/programming_rules.shtml|title=. Programming Rules and Conventions|last=Klas Eriksson, M. Williams, J. Armstrong|date=2 грудня 2013|website=http://erlang.se/doc/programming_rules.shtml|publisher=Ericsson AB|language=англійська|accessdate=2022-08-16|archive-date=2013-11-30|archive-url=https://web.archive.org/web/20131130121046/http://www.erlang.se/doc/programming_rules.shtml}}</ref>
 
=== Типи та аналіз коду ===
Програма Dialyzer, розроблена в рамках проєкту HiPE. Вона входить до стандартної поставки і дозволяє виявити помилки (у тому числі помилки типізації) шляхом [[Статичний аналіз коду|статичного аналізу коду]]. Програма TypEr, написана Тобіасом Ліндалом (Tobias Lindahl) та Костісом Сагонасом (Kostis Sagonas), є частиною Dialyzer. TypEr дозволяє перевіряти визначення типів функцій, звіряти вказаний у директиві <code>-spec</code> тип функції з її визначенням, виконати виведення типів. Програма виводить всі типи, що відповідають успішному застосуванню функції, в загальному випадку лише приблизно, в більш грубий бік. Використання функції будь-яким іншим чином обов'язково призведе до помилки часу виконання. У наступному прикладі показаний синтаксис визначення типу (директива <code>-type</code>), оголошення типу полів запису та директива <code>-spec</code> разом з визначенням функції<ref name=":1" />:<syntaxhighlight lang="erlang" line="1">
-type(user_status() :: disabled | enabled). % статус - один з двох атомів
 
-record(user, {login="anon" ::string(), % типи полів запису
password ::string(),
status :: user_status(),
nickname ::string()}).
 
-spec(check_password(string(), #user{}) -> ok | {error, string()}). % декларація функції
 
check_password(Password, User) -> % визначення функції
...
</syntaxhighlight>
Dialyzer (від {{Lang-en|DIscrepancy AnaLYZer for ERlang Programs}}&nbsp;— «аналізатор суперечностей для Erlang-програм») програма для виявлення в коді окремих модулів і в окремих додатках, помилок типів, [[Недосяжний код|недосяжного коду]] та надлишкових перевірок. Усі виявлені Dialyzer дефекти вимагають усунення, бо інструмент не дає помилкових спрацьовувань. Для кожної функції всіх модулів, що перевіряються, Dialyzer, встановлює тип, використовуючи заснований на обмеженнях вивід типів і аналіз потоків даних. Після визначення типів функцій проводиться аналіз протиріч у програмі.<ref>{{Cite book
|title=A Scalability Benchmark Suite for Erlang/OTP
|last=Aronis, Stavros and Papaspyrou, Nikolaos and Roukounaki, Katerina and Sagonas, Konstantinos and Tsiouris, Yiannis and Venetis, Ioannis E.
|year=2012
|publisher=Proceedings of the Eleventh ACM SIGPLAN Workshop on Erlang Workshop. Erlang '12.
|location=Copenhagen, Denmark: ACM.
|pages=pp. 33—42
|language=англійська
|isbn=978-1-59593-766-7.
}}</ref>
 
=== Тестування, профілювання, рефакторинг ===
Для [[Модульне тестування|модульного тестування]] Erlang надає EUnit. Для [[Системне тестування|системного тестування]] Erlang надає фреймворк Common Test. EUnit містить засоби для опису тестів, в тому числі необхідний для цього набір макросів, а також виводить звіт по закінченню тестування. Тестування модулів відбувається шляхом підключення заголовного файлу з EUnit, а функції з тестами можуть бути як включені в сам модуль, що тестується, так і винесені в окремий модуль.<ref name=":1" />
 
Тестування паралельних програм можна виконати за допомогою Quviq Quick Check (версія Mini безкоштовно). Крім тестування, можна здійснити перевірку всіх можливих варіантів вихідних даних за допомогою методу [[Перевірка моделі|перевірки моделей]]. Для цього є, створена в Мадридському політехнічному університеті, утиліта McErlang. [https://github.com/fredlund/McErlang]<ref name=":1" />
 
Щоб [[Профілювання (програмування)|профілювати]] код та виявити ступінь [[Тестування програмного забезпечення|покриття коду тестами]] можна звернутися до модулів <code>eprof</code>, <code>fprof</code>, <code>cover</code> та [[Утиліта|утиліти]] cprof.<ref name=":2" />
 
Для Erlang розроблена низка інструментів [[рефакторинг]]у вихідного коду (список не є вичерпним):
 
* RefactorErl,
* Wrangler,
* автоматична, незалежна від [[Інтегроване середовище розробки|IDE]] утиліта tidier.
 
Утиліта tidier дозволяє автоматично знаходити та виробляти еквівалентні перетворення коду, наприклад, замінює<syntaxhighlight lang="erlang" line="1">
lists:filter(fun (X) -> is_something(X) end, L)
</syntaxhighlight>на<syntaxhighlight lang="erlang" line="1">
[X || X <- L, is_something(X)]
</syntaxhighlight><ref>{{Cite book
|title=Cleaning Up Erlang Code is a Dirty Job but Somebody's Gotta Do It
|last=Avgerinos, Thanassis and Sagonas, Konstantinos.
|year=2009
|publisher=Proceedings of the 8th ACM SIGPLAN Workshop on ERLANG ACM,
|location=Edinburgh, Scotland:
|language=англійська
|deadurl=https://dl.acm.org/doi/10.1145/1596600.1596602
}}</ref>
 
=== Ефективність ===
Erlang має свої секрети написання ефективного коду. Удосконалення мови робить деякі з трюків застарілими, тому документація є найкращим посібником у питаннях оптимізації, у сукупності з профілюванням та [[Стрес-тестування програмного забезпечення|стрес-тестуванням]].
 
Наприклад, при роботі зі списками не бажано додавати елемент до кінця довгого списку за допомогою конкатенації або функції додавання елемента до списку. Зате можна додати елемент до початку списку, а кінцевий результат обробити функцією звернення порядку елементів списку.<syntaxhighlight lang="erlang" line="1">
L1 = [New_Elem | List].
L2 = lists:reverse(L1).
</syntaxhighlight>Є свої рекомендації і для підвищення ефективності паралельних програм. До прикладу, дії, що вимагають багато пам'яті, найкраще виділяти в окремий процес, бо при цьому зменшуються витрати на збирання сміття. Тоді пам'ять швидше буде звільнено після завершення процесу.<ref name=":1" />
 
== Erlang та інші мови програмування ==
 
=== Інтеграція та гібридні мови ===
Erlang-система дозволяє виконувати інтеграцію з системами на інших мовах програмування. Є механізми для мережевої взаємодії з [[C (мова програмування)|С]], [[Java]], [[Lisp|Лісп]], [[Perl]], [[Python]], [[Ruby]]. До прикладу, для ефективнішого синхронного виклику невеликих функцій на C можна використовувати платформно-залежні функції ({{Lang-en|NIF, natively implemented function}}). Високорівневі бібліотеки дозволяють Erlang-системі представляти C або Java-вузли як звичайні Erlang-вузли. Інші мови можна пов'язати з середовищем виконання Erlang за допомогою [[драйвер]]ів або мережевих [[Сокет (програмний інтерфейс)|сокетів]] за допомогою протоколів на кшталт [[HTTP]], [[SNMP]], IIOP. До прикладу, Ruby взаємодіє з Erlang за допомогою пакета erlectricity, а для Python розроблена реалізація Erlang-вузла у вигляді пакету py-interface.<ref name=":7" />
 
Віртуальна машина Erlang знаходить застосування і в інших мовах програмування. До прикладу, [[Elixir (мова програмування)|Elixir]] та проєкт Erl2 Джо Армстронга. Крім того, Роберт Вірдінг підтримує проєкт Lisp Flavored Erlang («Erlang, приправлений Ліспом»), у якому синтаксис [[Lisp|Ліспа]] використовується з компілятором<ref>{{Cite web|url=https://lfe.github.io/|title=Lisp Flavored Erlang|language=англійська|website=https://lfe.github.io/}}</ref> Erlang. Є й інші BEAM-мови: Efene, Joxa, Reia<ref>{{Cite web|url=http://www.unlimitednovelty.com/2011/06/why-im-stopping-work-on-reia.html|title=Why I’m stopping work on Reia|date=JUNE 29, 2011|website=http://www.unlimitednovelty.com/2011/06/why-im-stopping-work-on-reia.html|language=англійська}}</ref>, Luerl, Erlog<ref>{{Cite web|url=http://spawnedshelter.com/|title=Federico Carrone, et al Spawned Shelter!|date=15 вересня 2013|website=http://spawnedshelter.com/|language=Англійська}}</ref>.