| Erlang | |
|---|---|
| Парадигма | мультипарадигмальна:паралельна,функційна |
| Дата появи | 1987 |
| Творці | Джо Армстронг (програміст) |
| Розробник | Ericsson |
| Останній реліз | 25 (18 червня,2022; 3 роки тому (2022-06-18)) |
| Система типізації | динамічна типізація,сильна типізація |
| Під впливом від | Prolog,SmalltalkLisp,PLEX |
| Вплинула на | F#,Clojure,Rust,Scala,Opa,Reia,Akka,Dart,Elixir,Oz,Go |
| Мова реалізації | Erlang[1] |
| Операційна система | багатоплатформова |
| Ліцензія | Apache 2.0 |
| Звичайні розширення файлів | .erl, .hrl |
| Репозиторій вихідного коду | github.com/erlang/otp |
| Вебсайт | www.erlang.org |
Erlang (Ерла́нґ /ˈɜːrlæŋ/UR-lang) —мовафункційного програмування здинамічною типізацією, призначена для розробки програм для різного родурозподілених ібагатониткових систем. Розроблена і підтримується компанієюEricsson. Мова містить в собі засоби породження паралельнихпроцесів та їхньоївзаємодії за допомогою посиланняасинхронних повідомлень, без використання блокувань.
Мова орієнтована на розробку розподілених відмовостійкихзастосунків, які забезпечують паралельну обробку запитів врежимі реального часу. Мова набула поширення в таких областях, яктелекомунікації,банківські системи,електронна комерція,комп'ютерна телефонія і організаціямиттєвого обміну повідомленнями.
Програма транслюється вбайт-код, який виконуєтьсявіртуальною машиною, що забезпечує переносність. Одночасно розробниками випускається OTP (Open Telecom Platform) — супутній набірбібліотек і компонентів для розробки розподілених систем на мові Erlang. Код проєкту поширюється під модифікованою вільною ліцензієюMPL.
Свій синтаксис і деякі концепції, мова Erlang успадкувала від мови логічного програмуванняПролог. Мова підтримуєзіставляння зі взірцем, обробку виключень, спискові та бінарні генератори,анонімні функції,функції вищого порядку, обмін повідомленнями між процесами. Препроцесор підтримує роботу змакросами і включення заголовкових файлів.
Популярність мови Erlang зросла у зв'язку з розширенням області використання (телекомунікаційні системи) на паралельні розподілені системи з високим навантаженням, які обслуговують мільйони користувачівWWW, такі якчати,системи керування веб-контентом, веб-сервери і розподіленібази даних, що вимагають масштабування. Erlang використовуються в деякихNoSQL-базах данихвисокої доступності[2].
Серед малообізнаних з історією мови Erlang людей поширена думка, що назва «Erlang» розшифровується якERicssonLANGuage. Насправді мова отримала свою назву на честьАгнера Крарупа Ерланга[en], данського математика, який працював у галузітелекомунікацій. Існує одиниця вимірювання телекомунікаційного трафіку, яка також називаєтьсяErlang[en].[3]
На створення Erlang вплинулиML,Miranda[en],Ada,Модула-2[en],CHILL,Пролог. Окрім того, на спосіб оновлення програмного забезпечення вплинулиSmalltalk і пропрієтарні мови EriPascal та PLEX, якими послуговувались в Ericson[4].
Мова Erlang була створена в1986 році в лабораторії компаніїEricsson спільноДжо Армстронгом (Joe Armstrong),Робертом Вірдінгом (Robert Virding) іМайком Вільямсом (Mike Williams), і в1998 році переведена в розрядвідкритих проєктів. Завдяки початковій орієнтації на створеннязастосунків дляпаралельної обробки запитів в режимі реального часу мова набула поширення в таких областях яктелекомунікації,банківські системи,електронна комерція,комп'ютерна телефонія і організаціямиттєвого обміну повідомленнями[5].

У 1998 роцітоп-менеджмент Ericsson вирішив не брати на себе зобов'язань з розробки та підтримки власної мови програмування, натомість зосередившись наJava. Використання Erlang було заборонено у нових проєктах Ericsson Radio AB у зв'язку з реалізацією плануаутсорсингу програмної технології компанії Rational Inc.[6]
Це рішення дуже сильно вплинуло на майбутнє Erlang: воно призвело до відкриття коду Erlang підвідкритою ліцензією EPL (аналогMozilla Public License), а також послужило головною причиною початку поширення мови за межами компанії, що його створила. Основним запереченням проти відкриття вихідного коду було вирішення питань щодо патентів, але ці труднощі були подолані. Незабаром багато хто з основних розробників покинув Ericsson, щоб організувати власний бізнес — Bluetail AB.[4]
На початку 2000-х років наукові кола стали виявляти інтерес до Erlang. З 2002 року став проводитись щорічний Erlang Workshop. Ericsson продовжував спонсорувати проєкт HiPE (відангл.High-Performance Erlang — високопродуктивний Erlang). Проєкт HiPE займався ефективною реалізацією мови та інструментами для перевірки типів, і створений у групі проєкту компілятор в машинний код, який входить у постачання версії Erlang/OTP, вільно розповсюджується з 2001 року. Роботи, пов'язані з Erlang, ведуть інші заклади вищої освіти. Інструменти длярефакторингу створені в Кентському університеті у Великій Британії тауніверситеті Лоранда Етвеша в Угорщині, інструменти для різних видівтестування — у Мадридському політехнічному університеті,технічному університеті Чалмерса таГетеборгському університеті.
Коли системи з симетричною багатопроцесорністю тільки починали завойовувати ринок серверів і настільних комп'ютерів, кидаючи виклик розробникам програмного забезпечення, вже в 2006 перша версія Erlang з підтримкоюSMP була випущена спільними зусиллями команди OTP з Ericsson і команди HiPE. Незабаром після цього вийшла перша майже за десятиліття велика монографія з Erlang: «Programming Erlang» Джо Армстронга, після чого багато розробників «відкрили» для себе Erlang/OTP, і мова стала набирати популярності.[7]
Процес розвитку мови включає в себе розгляд пропозицій з розвитку EEP (Erlang Enhancement Proposal). За допомогою цих пропозицій Erlang-спільнота вносить зміни у стандартну подачу Erlang. З внесеними пропозиціями можна ознайомитися на веб-сторінціerlang.org/eeps.
За свідченнями Майка Вільямса, Erlang створювався для вирішення трьох проблем розробкирозподіленихсистем м'якого реального часу з високим ступенемпаралелізму:
За словами Вільямса, філософія, якої дотримувались розробники Erlang, пасує і для написанняпрограмного забезпечення цією мовою:[8]
Оригінальний текст(англ.) [
|
Більшість мов, створених раніше за Erlang, були розроблені без попереднього знаходження застосування, тоді як Erlang був розроблений спеціально на основі вимог до розподілених, стійких до відмов, паралельних систем реального часу. З розвитком Інтернету виявилося, що багато програм мають аналогічні вимоги, що пояснює зростання інтересу до мови.[9]
Секрет високої стійкості до відмов полягає у використанні ізольованих один від одного легких процесів, пов'язаних лише механізмом обміну повідомленнями та сигналами виходу. Принципи розробників на Erlang стосовно обробки помилкових ситуацій у процесах, можна виразити у вигляді висловлювання: «Let it crash»[10]. Пов'язано це з тим, що в Erlang-системі легко стежити за завершенням процесу, завершувати процеси, пов'язані зі збоями, і запускати нові процеси.[11]
Синтаксис успадкований від мовиProlog. Підтримуємодулі,поліморфні функції, зіставлення за шаблоном,анонімні функції, умовні конструкції, структури,обробку винятків, оптимізаціюхвостової рекурсії.
Головна риса Erlang — модель легких процесів. Процеси є дешевими, їхнє створення вимагає таку кількість ресурсів, що їх можна порівняти з викликом функції. Єдиним способом взаємодії процесів є асинхронний обмін повідомленнями. Процес може встановити зв'язок (link) з іншими процесами і за вибором або отримувати повідомлення про їхнє дострокове завершення з вказанням причини або розділити їхню долю. Процес має свою «поштову скриню», звідки може вибірково читати повідомлення. Мова програмування Erlang сприяє створенню великої кількостіконкурентних процесів. Процеси ізольовані та не мають спільного стану.
Процес проєктування полягає в ітеративному розбитті системи на ієрархії підсистем, які конкурентно взаємодіють, доки складові не стануть достатньо простими для реалізації.
Сув'язь «Процеси + повідомлення» на відміну від сув'язі «Об'єкти + Інтерфейси + Успадкування» часто дає компактніші рішення. Відсутність потреби блокування доступу до стану процесу для синхронізації їхньої взаємодії суттєво спрощує програмування. Для конкурентного ресурсу зазвичай створюється процес-монітор, через який здійснюється взаємодія з ресурсом.
Також важливий момент полягає у формулі «let it crash» («нехай процес впаде»). Замість перехоплювати помилки і намагатися продовжувати роботу, частина програми, що містить ризикований код, відокремлюється у незалежний процес-камікадзе, який система вбиває у випадку виникнення помилки, при цьому батьківський процес отримує повідомлення про смерть нащадків і, за потреби, може перезапускати ці процеси. Такий підхід позбавляє код численних перевірок.
Erlang єдекларативною мовою програмування, яка використовується більше для опису того,що має бути обчислено, ніжяк. Наприклад, визначення функції, яке використовуєзіставлення зі зразком для вибору одного з варіантів обчислення або вилучення елемента даних зі складової структури нагадуєрівняння.Зіставлення зі взірцем поширене навіть на бітові рядки, що спрощує реалізацію телекомунікаційних протоколів.[8]
Функції єоб'єктами першого класу Erlang. У мові також широко застосовуються характерні дляфункціональної парадигми програмуванняспискові включення (генератори списків).[8]

Особливістю мови Erlang є застосуваннялегковагих процесів відповідно домоделі акторів. Такий підхід дозволяє виконувати одночасно сотні тисяч і навіть мільйони таких процесів, кожен з яких може мати скромні вимоги допам'яті. Процеси ізольовані один від одного і не мають загального стану, але між ними можна встановити зв'язок та отримувати повідомлення про їхній стан.[8]
Для взаємодії процесів використовують асинхронний обмін повідомленнями. Кожен процес має своючергу повідомлень, обробка якої використовуєзіставлення із взірцем. Процес, що надіслав повідомлення, не отримує повідомлення про доставку, навіть якщо ідентифікатор процесу одержувача недійсний або одержувач ігнорує повідомлення. Таким чином, відповідальність за правильно організовану взаємодію між процесами лежить на розробникові.[9]
Наприклад, при реалізації на Erlang мережевогочату, структура програми може безпосередньо відображати одночасність дій користувачів щодо обміну повідомленнями шляхом запуску нових процесів. Ефективність передачі повідомлень зберігається зі збільшенням кількості процесів, а вимоги до пам'яті мінімізуються за рахунок того, що легковагими процесами керує віртуальна машина, а не засобиопераційної системи.[8]
Erlang з самого початку проєктувався длярозподілених обчислень тамасштабованості. Підтримка паралелізму вбудована всинтаксис тасемантику мови, тому побудову системи можна вести, абстрагуючись від конкретного місця обчислень. У стандартній поставці Erlang може налагодити зв'язок процесів протоколуTCP/IP незалежно від підтримуваних ним платформ (операційних систем).[8]
Запущений екземпляр емулятора Erlang називаєтьсявузлом (node). Вузол має ім'я і «знає» про існування інших вузлів на цій машині або у мережі. Створення та взаємодія процесів різних вузлів не відрізняється від взаємодії процесів всередині вузла. Програми, написані на Erlang, здатні працювати на кількох вузлах. Вузлами можуть бути процесори, багатоядер одногопроцесора, і навіть цілий кластер машин. Для створення процесу на іншому вузлі процесу достатньо знати його ім'я і, без особливих підстав, він може не цікавитися фізичним розташуванням процесу, що з ним взаємодіє. Синтаксис відправки повідомлення процесу на своєму вузлі та віддаленому однаковий.[8]
Завдяки вбудованим у мову можливостям розподілених обчислень об'єднання вкластер,балансування навантаження, додавання вузлів та серверів, підвищення надійності викликають лише невеликі витрати на додатковий код. За замовчуванням, вузли спроєктовані для роботи всередині відокремленого сегмента мережі (DMZ), але, якщо необхідно, комунікація між вузлами може відбуватися із застосуванням протоколуSSL, захищеногокриптографічними методами.[8]
Програми високорівневою мовою Erlang можуть бути використані в системахм'якого реального часу (який іноді перекладають як «псевдореальний» або «квазіреальний»). Автоматизоване керування пам'яттю тазбирання сміття діють у рамках одного процесу, що дає можливість створювати системи з мілісекунднимчасом відгуку (навіть незважаючи на необхідність збирання сміття), що не відчувають погіршенняпропускної здатності при високому навантаженні.[8]
Для систем, які не можуть бути зупинені дляоновлення коду, Erlang пропонує гарячу заміну коду (англ.hot code upgrade). При цьому в додатку можуть одночасно працювати старі і нові версії коду. У такий спосіб програмне забезпечення на Erlang може бути модернізовано без простоїв, а виявлені помилки виправлені.[12]
Типізація в Erlang є сильною тадинамічною. Динамічна типізація була обрана для мови Erlang через те, що перші розробники були більше з нею знайомі.[13] На думку Джо Армстронга, статична типізація вимагала б дуже великих трудовитрат, зокрема, реалізувати систему гарячого дозавантаження коду було б дуже важко. Такатипізація, коли можливі помилки типів виявляються лише під час виконання, не завадила можливості створювати системи з дужевисоким рівнем доступності. Дані Erlang єнезмінними: операції не переписують старі значення, що знаходяться в пам'яті. Якщо необхідно, модулі на Erlang можна забезпечити описами та визначеннями нових типів (що не впливають на компіляцію програми) для автоматичної перевірки типів за допомогою утиліти Dialyzer.[13]
У Erlang є два типи числовихлітералів:цілі і зрухомою комою, наприклад:125,4.5e-20. Крім звичайної нотації, числа можна задавати через символASCII (наприклад,$B означає66) або разом із зазначенням системи числення з основою від 2 до 36 (у старих версіях — до 16), наприклад:16#3f,2#1010. У Erlang застосовуються цілі числадовільної точності тадійсні числа подвійної точності (64біти), у стандартіIEEE 754—1985. Для роботи з числами можна використовувати модульmath, який містить звичайний набір математичних функцій та функціюmath:pi/0, що повертаєчисло.[14] Приклад обчислень в інтерактивній оболонці:
Erlang/OTP23[erts-11.2.2.4][source][64-bit][smp:20:20][ds:20:20:10][async-threads:1][hipe]EshellV11.2.2.4(abortwith^G)1>123/23+12*(2+3).65.347826086956522>math:cos(math:pi()).-1.03>random:uniform(10).5
Атом — константа з ім'ям, що має бути взята в одинарні лапки, якщо не починається з малої літери або містить знаки, окрім літер, цифр, підкреслення, крапки та символу@. Поняття атома запозичене зProlog та його можна вважати аналогомперерахувань (enum) в інших мовах програмування (без необхідності попередньої декларації).[15] Атоми використовуються майже виключно в порівняннях (та взіставленні зі взірцем (en: Pattern matching)), та мають Erlang дуже ефективну реалізацію. Крім того, деякі атоми мають певний сенс у значеннях, що повертаються, і описі винятків. До них відносяться, наприклад:error,ignore,noreply,ok,reply,stop,undefined.
Бітовий рядок використовується для зберігання пам'яті нетипізованих даних. Рядки, що складаються з цілої кількостіоктетів, називаютьсябінарними (абодвійковими)даними (англ.binaries). Синтаксис опису бітового рядка досить гнучкий, оскільки визначає значення бітів окремих діапазонів і може бути забезпечений модифікатором типу.[8] Декілька прикладів в інтерактивній командній оболонці:
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>>
Конструктори бітових рядків (англ.bitstring comprehension) аналогічні списковим генераторам, але працюють над бітовими рядками:
1> << <<bnot(X):1>> || <<X:1>> <= <<2#111011:6>> >>.<<4:6>>
У цьому прикладі змінна X послідовно отримує біти числа2#111011, які потім інвертуються операцією бітового запереченняbnot (відангл.binary NOT), внаслідок чого виходить число 4.[8]
Кортеж (англ.tuple) — складений тип даних з фіксованою кількістю елементів. При доступі до елементів кортежу за допомогою вбудованих функцій, нумерація елементів починається з одиниці, а не з нуля. Перший елемент кортежу (атом) можуть використовувати для опису ролі кортежу у програмі — його називають тегом (англ.tag — «мітка»). В Erlang прийнято будувати різні типи даних на основі кортежів з тегами, це полегшуєзневадження програми та вважається гарним стилем програмування.[8]
Для роботи з кортежами є декілька вбудованих функцій, наприклад:[8]
1>tuple_size({a,1,"777"}).32>element(1,{b,2,3,4}).b3>setelement(1,{c,5},d).{d,5}
Список (англ.list) — складений тип даних зі змінною кількістю елементів. Для маніпуляції зі списками можна використовувати функції модуляlists стандартної бібліотеки. Формально список визначається як структура, яка має голову (англ.head) та хвіст (англ.tail), що виражається синтаксично у вигляді[HEAD|TAIL], де хвіст зазвичай є списком (можливо порожнім). Порожній список позначається[][8]
Списки можна записувати і більш звичним способом. Наступні записи еквівалентні:
1> [a|[b|[c|[]]]].[a,b,c]
Для роботи зі списками можна використовувати конструктори списків[13](генератори списків — en: List Comprehensions), наприклад:
1>[X/2||X<-[1,2,3,4]].[0.5,1.0,1.5,2.0]
Модульlists стандартної бібліотеки містить функції для роботи зі списками (та рядками, оскільки рядок виду «test» в Erlang є списком кодів символів)[8], такі як знаходження найбільшого значення, сортування, зміни порядку елементів на протилежний, отримання суми елементів тощо. У наступному прикладі «склеюємо» два списки в один за допомогоюконкатенації, і далі розбиваємо на два списки функцієюlists:split/2:
1>lists:split(2,[l,2,3]++[4,5,6]).{[l,2],[3,4,5,6]}
А це приклад того, що рядок виду «test» в Erlang є списком кодів символів:
1>"test"=:=[$t,$e,$s,$t].true2>"test"=:=[116,101,115,116].true3>$t.116
У модуліlists є також набірфункцій вищого порядку, таких якlists:all/2,lists:any/2,lists:dropwhile/2,lists:filter/2,lists:foldl/3,lists:foldr/3,lists:map/2,lists:foreach/2.
lists:map/2 — функція вищого порядку, яка дає можливість застосувати визначену нами функцію до кожного елемента списку, в результаті отримаємо новий список:
third_degree(R)->lists:map(fun(X)->math:pow(X,3)end,R).
В даному прикладі функція math: pow(X, 3) підносить до степеня 3 кожен елемент списку R.
lists:filter/2 — дана функція вищого порядку приймає два параметри: функцію (предикат), за допомогою якої ми відфільтровуємо наш список — другий параметр. Повертає новий список — результат обробки фільтром вхідного списку.
multiple_three(List)->lists:filter(fun(X)->Xrem3=:=0end,List).
В даному прикладі з вхідного списку List у новий — вихідний список попадуть лише елементи, кратні трьом.lists:foldl/3 — функція лівої згортки (англ. fold — згорнути, «l» від англ. left — лівий) приймає 3 аргументи:
Функція згортання приймає два аргументи: поточний елемент списку та поточне значення акумулятора. І повертає нове значення акумулятора.
Класичні приклади — обчислення суми та добутку елементів масиву:
1>Numberlist=[11,12,13,14,15].[11,12,13,14,15]2>lists:foldl(fun(Item,Acc)->Acc+Itemend,0,Numberlist).653>lists:foldl(fun(Item,Acc)->Acc*Itemend,1,Numberlist).360360
Наступний приклад ілюструє роботу функції правої згортки lists: foldr (англ. fold — згорнути, «r» від англ. right — правий), першим параметром якої має бути функція:
1>D=fun(V,A)->V/Aend.% функція D - ділення V на A#Fun<erl_eval.12.82930912>2>lists:foldr(D,1,[1,2,4,8]).0.253>1/(2/(4/(8/1))).0.25
Результат виконання згортки справа наліво (у рядку 2) тотожний ланцюжковому поділу (рядок 3). Другий параметрfoldr — початкове значення так званого акумулятора. Для кожного елемента списку (справа ліворуч) до елемента та акумулятора застосовується функція, задана першим аргументомfoldr, а значення записується в акумулятор. За вичерпанням списку, функція повертає значення акумулятора. Функція є досить потужним засобом, якщо врахувати, що акумулятор може бути списком або кортежем.[9]
Зазвичай користуються foldl — тому, що операція отримання елементу-голови списку виконується за константний час, а для отримання елементу з кінця списку потрібно пройтись через весь список[16].
У Erlang немає самостійного типу длярядків — внутрішньо рядки є списками кодів символів. Рядок"Привіт!" рівносильний (у відповідному кодуванні) списку[1055,1088,1080,1074,1077,1090,33]. Для правильної інтерпретації списків кодів символів як рядків в інтерактивній консолі — запускайте з відповідним параметром:$ erl +pc unicode. Erlang підтримуєUnicode як у рядку, так і запису окремого символу ($X, де X — деякий символ).[9]
Бінарні послідовності записуються та відображаються, як послідовності цілих чисел або рядків, поміщені між подвійними символами< та>. Для прикладу:
1><<5,10,20>>.<<5,10,20>>2><<"hello">>.<<"hello">>
term_to_binary(Term) -> Bin — Конвертує будь-який терм Erlang у бінарну послідовність.[16]
Бінарна послідовність, вироблена за допомогою term_to_binary, зберігається в так званому зовнішньому форматі терму. Терми, які були конвертовані в бінарні послідовності з використанням term_to_binary, можуть бути збережені в файли, передані в повідомленнях по мережі тощо, а початковий терм, з якого вони були зроблені, може бути відновлений пізніше. Це надзвичайно корисно для збереження складних структур даних у файли або надсилання складних структур даних на віддалені машини.[16]
1>B=term_to_binary("useful").<<131,107,0,6,117,115,101,102,117,108>>2>binary_to_term(B)."useful"
Атоми і рядки зовні досить схожі, але мають різні реалізації. Тоді як атоми можна лише порівнювати, рядки підтримують багато інших операцій, їм є безліч функцій в модуляхlists іstring. Рядок може виконувати функції атома, але пам'ять, яку займає рядок, пропорційна його довжині, тоді як атоми зберігаються в системній таблиці і на кожне зберігання/пересилання атома в програмі припадає лише декілька байтів, незалежно від довжини атома. Порівняння двох атомів — це порівняння двох внутрішніх ідентифікаторів, яке виконується за одну операцію, тоді як порівняння рядків передбачає поелементний прохід, тобто порівняння кодів символів — елементів списків.[8]
Для значень булевої логікиістинне тахибне в Erlang застосовуються атомиtrue (істинне) іfalse (хибне), які використовуються операціями порівняння, логічними операціями, вбудованими функціями.[8] Приклад:
1>2<3.true2>is_boolean(125).false
Fun-вираз дозволяє створити анонімну функцію (лямбда-функцію), яка використовується, наприклад, для передачі аргументом в іншу функцію. За допомогоюfun можна також отримати функціональний об'єкт для функції модуля.[9] Приклади:
1>lists:map(fun(X)->X+1end,[1,2,3]).[2,3,4]2>Belongs=funlists:member/2.#Fun<lists.member.2>3>Belongs(a,[a,b]).true
Щоб позначати окремі елементи кортежів (полегшити роботу з великими кортежами) і уникнути помилок при написанні програми, в Erlang було додано синтаксичний цукор — синтаксисзаписів (англ.record). Записів не існує в час виконання — на етапі компіляції записи перетворюються (транслюються) в кортежі — ключі губляться, відповідно, в час виконання існують лише значення записів. Для роботи з записами, необхідно спочатку дати опис запису директивою-record, наприклад, для записуuser опис може бути наступним[17]
-record(user,{login="anonymous",email,password}).
З цього опису компілятор дізнається, що маються на увазі кортежі з чотирьох елементів, в яких елементи з другого по четвертий відповідають полямlogin,nick,password запису з ім'ямuser (визначається атомом в першому елементі кортежу). Значенням за замовчуванням для поляlogin є рядок"anon". Якщо значення за замовчуванням не вказано явно, таким є атомundefined.
Створення записів та вилучення елементів запису завжди вимагає явної вказівки імені запису:[17]
R0=#user{},% всі поля отримують значення за замовчуваннямR1=#user{login="user1",email="user@mail.com",password="secret"},% Задаємо значення для всіх полів
Оновлення одного значення в наявному записі:R2 = R1#user{login = "user2"},
оновлення двох значень в наявному записі:R2 = R1#user{login = "user2", email = "neo@matrix.org"},
отримати значення по ключу з записуNick2 = R2#user.nick..
Асоціативний масив (словник) (en: map) зберігає пари виду «(ключ, значення)». І ключем, і значенням може бути будь-який терм Erlang.[18]
Map=#{a=>2,b=>3,c=>4,"a"=>1,"b"=>2,"hi"=>42},Key="hi",maps:find(Key,Map).{ok,42}
У мові Erlang є інші типи даних. Типпосилання (англ.reference) є унікальним у межах вузла/кластера з'єднаних вузлів в середовищі часу виконання Erlang. Посилання створюється викликом функціїmake_ref/0 і може повторитися через 282 викликів цієї функції. Посилання можна порівнювати на рівність, а застосовуються вони для одноразових позначок або«чарівного печива»[17]
Ідентифікатор порту (англ.port identifier) визначає порт для зв'язку із зовнішнім по відношенню до Erlang-системи світом. Порт дозволяє процесу, що його створив-власнику (так званому приєднаному процесу) обмінюватися бінарними повідомленнями зі сторонніми програмами і ОС способом, прийнятим в даній операційній системі.[17][19]
Ідентифікатор процесу (англ.Pid), як і випливає з його назви, ідентифікує процес, що породжується різними функціямиspawn. Ідентифікатор можна вважати унікальним під час роботи Erlang-системи, але в системах, що довго працюють, можуть все-таки бути використані повторно, що зазвичай не є проблемою на практиці.[17]
Для перетворення типів використовуються вбудовані функції (BIF,англ.builtin function) виду x_to_y («з x в y»), а для перевірки належності значення того чи іншого типу — функції виду is_x («є_x»):
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).true2>is_tuple("abc").false3>is_integer(3.0).false
Erlang надає найбільш поширені арифметичні операції для цілих чисел ічисел з плаваючою комою:
| Позначення | Операція, що виконується | приклад | Результат прикладу |
|---|---|---|---|
+ | Унарний плюс | +3 | 3 |
- | Унарний мінус | -3 | -3 |
+ | Додавання | 2+3 | 5 |
- | Віднімання | 7-3 | 4 |
* | множення | 1.2*0.4 | 0.48 |
/ | Ділення | 5 / 3 | 1.6666666666666667 |
div | Цілочисельнеділення | 5 div 3 | 1 |
rem | Залишок відділення | 5 rem 3 | 2 |
Всі ці операціїлівоасоціативні. Унарні операції мають найвищий пріоритет, потім слідує множення і ділення, найменший пріоритет у складання та віднімання. При необхідності ціле може приводитися до типу з рухомою комою.[8]
Бітові операції працюють над цілими числами і дають в результатіціле число.[8]
| Позначення | Операція, що виконується | приклад | Результат прикладу |
|---|---|---|---|
bnot | Побітове заперечення | bnot (2#1000) | -9 |
band | Побітове І | 2 band 3 | 2 |
bor | Побітове АБО | 1 bor 2 | 3 |
bxor | Побітовевиключне АБО | 5 bxor 3 | 6 |
bsr | Побітовий зсув вправо | 32 bsr 2 | 8 |
bsl | Побітовий зсув вліво | 1 bsl 5 | 32 |
Логічні операції працюють над логічними значеннямиtrue (істинне) іfalse (хибне), одержуваними в результаті порівнянь та застосування функцій перевірки типу:[8]
| Позначення | Операція, що виконується | приклад | Результат прикладу |
|---|---|---|---|
not | Заперечення (НЕ) | not true | false |
and | Кон'юнкція (І) | true and (1 < 5) | true |
andalso | Аналогічноand, але не обчислює другий операнд, якщо першийfalse | false andalso (1 < 5) | false |
or | Диз'юнкція (АБО) | is_atom("1") or is_atom(1) | false |
orelse | Аналогічноor але не обчислює другий операнд, якщо першийtrue | true orelse (1 < 5) | true |
xor | Виключне АБО | true xor true | false |
Операції порівняння отримують два операнди, а результатом операції є логічне значенняtrue абоfalse. У Erlang є наступні операції:== (рівно),=:= (рівно, враховуючи тип — використовується для порівняння чисел),/= (не рівно),=/= (не рівно, враховуючи тип — використовується для порівняння чисел),=< (менше або дорівнює),< (менше),> (більше),>= (більше або дорівнює):
== перевірка на рівність (не враховуючи тип):
1>5==5.true2>5==5.0.true
=:= перевірка на рівність (враховуючи тип):
4>5=:=5.true5>5=:=5.0.false
Можна порівнювати значення різних типів, але вони вважаються в Erlang впорядкованими наступним чином:[8]число < атом < посилання < функція < порт < ідентифікатор процесу < кортеж < список < бінарні дані
Списки вважаються впорядкованими влексикографічному порядку, а кортежі порівнюються за довжиною, і лише потім у лексикографічному порядку.[8]
Змінні служать для зберігання значень простих і складових типів. Ім'я змінної починається з великої літери (у спеціальних випадках — з підкреслення) і може містити букви, цифри, підкреслення. Змінній можна присвоїти значення лише один раз — ця властивість мови програмування називається одиничним присвоєнням (англ.single assignment). До переваг одиничного присвоєння можна віднести усунення необхідності в блокуваннях, а також спрощення налагодження програми[20]
Відбувається обчислення(редукція) аргументів функції перед застосуванням функції до цих аргументів (вхідних параметрів).
Область видимості змінної поширюється від її визначення (en: bind — зв'язування) до закінчення клози функції. Приклад:
binomial(X)->Y=X*X,X+Y.prod([1|T])->prod(T);prod([Y|T])->Y*prod(T);prod([])->1.
У цьому прикладі область видимостіX — весь опис функціїbinomial/1, аY — від присвоєння до кінця опису. ЗміннаY у другій клозі функціїprod/1 не має відношення до змінноїY зbinomial/1: її область видимості поширюється до кінця цієї клози.[8]
При виході обчислень за межі області видимості змінної, пам'ять, зайнята її вмістом, може бути звільнена у процесізбирання сміття, якщо значення змінної не використовується в іншій частині програми.[17]
Зіставлення зі зразком (en: Pattern Matching) використовується в Erlang дляприсвоєння (у тому числі, при роботі з параметрами функцій), управління потоком виконання програми, отримання значень складових типів, вибору повідомлення з черги. У лівій частині порівняння (або в заголовку функції) можуть бути пов'язані (вже мають значення) і незв'язані (отримуючі значення) змінні, а також літерали (атоми, числа, рядки). В результаті виконання порівняння може виявитися успішним (у цьому випадку змінні зв'язуються зі значеннями) та неуспішним — змінні залишаються непов'язаними. У зразку можуть бути змінні, значення яких для зразка байдуже: їх імена записуються з підкреслення. Змінні, ім'я яких починається з підкреслення, це звичайні змінні, крім того, що компілятор не буде скаржитися, якщо вони не використані. Не можна прив'язувати до них значення більше одного разу.[8]
Програми Erlang складаються з функцій, які викликають одне одного. Кількість вхідних аргументів (параметрів) функції називаєтьсяарністю. При виклику функції заголовки функції зіставляються зі зразком. У разі збігу параметрів виклику формальні параметри зв'язуються з фактичними і виконується відповідна частина тіла функції. Запис варіанту обчислення функції для деякого зразка може називатисяклозом відангл.clause, а визначення функції — це набір з одного або більше клозів.
Для уточнення зіставлення зі зразком у функціях можна використовуватиохоронні вирази, які випливають після ключового словаwhen[9]. У прикладі нижче визначено функцію обчисленнязнака числа, яка розраховується в залежності від порівняння параметра з нулем:
sign(X)whenX>0->1;sign(X)whenX==0->0;sign(X)whenX<0->-1.
Erlang перебирає (матчить) клози функції в тому порядку, в якому вони записані (зверху вниз, зліва направо), доки не буде знайдено відповідний вираз (заголовок клози), який зматчиться.[9] В охоронних виразах можна використовувати лише обмежений набір вбудованих функцій, оскільки ці функції не повинні матипобічних ефектів.
Функції Erlang підтримуютьрекурсивні виклики. У разі коли визначення функції закінчується рекурсивним викликом (хвостова рекурсія), Erlang використовує оптимізацію: стек викликів не застосовується.[9]
Як параметром, і результатом функції може бути інша функція. У наступному прикладі функція одного аргументу повертає функцію додавання аргументу[8]
1>Plus=fun(X)->fun(Y)->X+Yendend.% Визначення функції, яка повертає функцію#Fun<erl_eval.6.82930912>2>Plus(2).% Функція повертає Fun-об'єкт#Fun<erl_eval.6.82930912>3>Plus(2)(3).% Такий синтаксис не працює*1:syntaxerrorbefore:'('4>(Plus(2))(3).% Додаткові дужки дозволяють досягти необхідного результату55>Plus2=Plus(2),Plus2(3).% Те саме з використанням додаткової змінної5
Окрім матчингу та охоронних виразів у клозах функції, в Erlang є інші умовні вирази вибору: if та case. Вираз вибору дозволяє організувати зіставлення зі зразком усередині функції і зазвичай має наступний синтаксис:
ifохорона1->вираз11,вираз12,...;охорона2->вираз21,вираз22,...;...охоронаN->виразN1,виразN2,...end
Тутохорона1— охоронний вираз (en: guards).[21] Охоронні вирази — розширення зіставлення зі зразком, що додаєвиразності. Без охоронних виразів ми не можемо визначати такі речі, як діапазон значень чи певні типи даних. У Erlang if — це вираз, який може мати декілька гілок. Гілки скануються послідовно, зверху донизу, допоки захисна послідовність не буде оцінена як true. Якщо охорона1 (перший guard в даному прикладі) поверне true одразу почнеться виконання відповідних виразів: вираз11, вираз12,… Після виконання цих виразів відбудеться вихід з блоку і наступні умовиохорона2, …, охоронаN перевірятися не будуть. Якщо жохорона1 повернеfalse, відбувається перехід до перевірки наступного охоронного виразу, і так доти, поки guard не поверне значення true, після чого будуть виконані відповідні, розділені комами вирази і вихід з блоку. Слід зауважити, що і тут в охоронному виразі можна застосовувати лише обмежений набір операцій та вбудованих функцій. Коми в охоронному вираженні працюють як операція andalso, крапка з комою — як orelse, наприклад:[9]
ifX=<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.
Якщо жодна захисна послідовність не є істинною, виникає помилка виконанняif_clause. При необхідності можна використовувати захисникtrue. В останній гілці, оскільки ця захисна послідовність завжди вірна, і вважається аналогом «інше».[16] Компілятор Erlang стежить за безпекою зв'язування змінних усередині умовних виразів, це ми можемо побачити на наступному прикладі:
-module(badexample).-export([broken_if/1]).broken_if(X)->ifX<0->Z=-1;X>=0->Y=1end,Y*Z.
При спробіскомпілювати модуль виникають повідомлення про помилки, тому що в такому коді змінні не пов'язуються зі значенням в іншій клозі відповідно:
1>c(badexample).badexample.erl:8:variable'Y'unsafein'if'(line4)badexample.erl:8:variable'Z'unsafein'if'(line4)error
Правильним було б визначити всі використовувані далі за кодом змінні у всіх гілках if-вирази.[9]
-module(if_else).-export([compare/2,ascii/1,run/3]).compare(X,Y)->Result=ifX>Y->greater;X=:=Y->equal;X<Y->lessend,io:format("~p is~p than~p~n",[X,Result,Y]).ascii(Letter)->Code=ifLetter=:='A'->101;Letter=:='B'->102;true->unknownend,io:format("~p =~p~n",[Letter,Code]).run(X,Y,Letter)->compare(X,Y),ascii(Letter).
Можна використовувати виразcase ... of для порівняння послідовності патернів. На відміну від виразуif, case ... of дає змогу використовувати охоронні вирази в пунктах зіставлення. Якщо жодний вираз case не відповідає зразку (не матчиться), система виконання викличе помилку про відсутність відповідності: «no case clause matching». Використовувати шаблон підкреслення_ можна, щоб захопити будь-яке інше значення, яким не відповідали попередні ключі.[5]
caseexpressionofpattern1[whenguard1]->expr_seq1;pattern2[whenguard2]->expr_seq2;...end.
Спочатку обчислюється expression, припустимо, що при цьому воно набуває значення Value. Далі Value зіставляється з pattern1 (разом з опціональним контролером guard1), pattern2 і так далі, до першого успішного зіставлення. Щойно це станеться, виконується послідовність виразів (expr_seqN) і результат цього обчислення стає результатом всього даного виразу. Якщо жоден із патернів не підійде, то відбувається виняткова ситуація.[16]
-module(case_of).-compile([export_all,nowarn_export_all]).admit(Person)->casePersonof{male,Age}whenAge>21->yes_with_cover;{female,Age}whenAge>21->yes_no_cover;{male,_}->no_boy_admission;{female,_}->no_girl_admission;_->unknownend.run(Person)->Record=admit(Person),io:format("~p~n",[Record]).
В функціональних мовах програмування відсутні цикли, натомість використовуєтьсярекурсія.
Розглянемо функції обчисленняфакторіалу:
-module(fact).-export([fac/1,func/1]).fac(0)->1;fac(N)whenN>0->N*fac(N-1).
Це рекурсія без хвостової оптимізації, вона добре працює для невеликої глибини рекурсії. Проте, стає проблематичною у випадку великої глибини рекурсії.
Чим більше операцій рекурсії — тим більше займе пам'яті дана програма у стеку при виконанні, дана рекурсія розгортається у стек — відповідно, чим більше рекурсивних викликів — тим більше пам'яті займе дана програма при виконанні.[16]
Хвостова рекурсія — це рекурсія, яка викликається останньою інструкцією, таким чином стек залишається незмінним (або ж практично незмінним) і функція може працювати перманентно без зупинки.[16]
func(N)->func(N,1).func(0,A)->A;func(N,A)whenN>0->func(N-1,N*A).
Хвостова рекурсія незалежна від кількості рекурсивних викликів — в пам'яті залишаються лише два числа.Спробуємо написати функцію обчислення N-ногочисла Фібоначчі на Erlang двома шляхами-алгоритмами. Спочатку звичайна рекурсія.
-module(fibonacci).-export([fib_usual/1,fib_tail/1]).fib_usual(1)->0;fib_usual(2)->1;fib_usual(N)whenN>0->fib_usual(N-1)+fib_usual(N-2).
Дана функція тримає всі числа-проміжні результати одночасно у памяті, і кількість рекурсивних викликів функції — активних процесів — зростає надто стрімко.Хвостова рекурсія в даному випадку пишеться з використанням двох тимчасових змінних в якості параметрів нашої функції. Такі змінні називаються акумуляторами та використовуються для зберігання проміжних результатів наших обчислень, щоб не зберігати багато незакінчених обчислень (процесів, які очікують результат розрахунків від інших процесів) у пам'яті.
fib_tail(N)whenis_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).
У памяті тримаються лише три числа та займається обчисленнями лише один процес.
Додамо декілька функцій, які працюють рекурсивно зі списком і виконують такі звичні для всіх нас завдання:
- визначення довжини масиву;
- знаходження максимального (мінімального) елемента масиву;
- обчислення суми всіх елементів масиву.
1. Визначення довжини масиву:
- спочатку звичайна рекурсія
len_list([])->0;len_list([_])->1;len_list([_H|T])whenis_list([_H|T])->1+len_list(T).
- хвостова рекурсія з акумулятором
length_tail(List)whenis_list(List)->length_tail(List,0).length_tail([],Acc)->Acc;length_tail([_|Tail],Acc)->length_tail(Tail,1+Acc).
2. Знаходимо максимальний елемент масиву:
- спочатку звичайна рекурсія
max_el([Last])whenis_number(Last)->Last;max_el([H|T])whenhd(T)>=H->max_el(T);max_el([H|T])->max_el([H|tl(T)]).
- та сама функція, з допомогою хвостової рекурсії і акумулятора
tail_maxx([H|T])whenis_number(H)->tail_maxx(T,H).tail_maxx([],Acc)whenis_number(Acc)->Acc;tail_maxx([H|T],Acc)whenH>=Acc->tail_maxx(T,H);tail_maxx([_|T],Acc)->tail_maxx(T,Acc).
3. Підрахуємо суму елементів масиву:
- звичайна рекурсія
sumx([])->0;sumx([H|T])->H+sumx(T).
- підрахунок суми елементів масиву з допомогою хвостової рекурсії
tail_sum(List)->tail_sum(List,0).tail_sum([],Acc)->Acc;tail_sum([H|T],Acc)->tail_sum(T,Acc+H).
Один з алгоритмів сортування —швидке сортування[12]
-module(qsort).-export([qsort/1]).qsort([])->[];qsort([Pivot|Rest])->qsort([Front||Front<-Rest,Front<Pivot])++[Pivot]++qsort([Back||Back<-Rest,Back>=Pivot]).
У цьому прикладі функціяqsort викликається рекурсивно до вичерпання всіх елементів. Вираз[Front || Front <- Rest, Front < Pivot] збирає списокFront з елементівRest таких, що елементFront менший заPivot. Оператор++склеює списки.
Препроцесор Erlang (EPP) дозволяє вкладати файли з вихідним кодом один в інший, визначатимакроси та здійснювати прості та параметризовані макропідстановки.[8] Макрос визначається за допомогою директиви-define, а макропідстановка здійснюється вказівкою імені макроса та можливих параметрів після знака питання (?). Наступний приклад показує визначення та застосування параметризованого макроса:
-define(ZERO(X),X==0).is_zero(T)when?ZERO(X)->true;is_zero(T)->false.
Ім'я макроса зазвичай пишеться великими літерами. Визначення макроса має міститилексеми Erlang цілком (наприклад, спроба задати частину імені змінної за допомогою макроса викликає синтаксичну помилку). Макроси можуть використовуватися для підвищеннязручності читання коду в охоронних виразах, для операторів налагодження і т. ін. Препроцесор має декілька визначених макросів, які не можна перевизначити:?MODULE,?MODULE_STRING,?FILE,?LINE,?MACHINE.[22]
Заголовний файл (розширення.hrl) з визначеннями макросів та записів можна включити за допомогою директиви-include.[8]
Для обробкивиняткових ситуацій Erlang можна застосовувати конструкціюtry ... catch, в загальному випадку записується в наступному вигляді[8]
tryвираздляобчисленняofзразок1whenохорона1->вираз1;зразок2whenохорона2->вираз2;...зразокNwhenохоронаN->виразNcatchкласс1:зразокВикл1whenохоронаВикл1->виразВикл1;...классМ:зразокВиклМ:StacktracewhenохоронаВиклМ->виразВиклМ;end
Як і у випадку case-виразу, вираз, що обчислюється, зіставляється зі зразком (частини міжof іcatch) для отримання результату.[9] Після ключового словаcatch слідують частини обробки винятків, у яких на додаток до зразків винятків можуть бути вказані класи винятків (перед двокрапкою):error,throw таexit. Stacktrace — це список викликів функцій, обчислення яких виконувала програма, коли було створено виняток. Підкреслення може використовуватись як у зразку, так і в класі виключення. Наступний простий приклад ілюструє перехоплення помилки класуerror при обчисленніквадратного кореня.
1>trymath:sqrt(-1)catcherror:Error->{error,Error}end.{error,badarith}2>trymath:sqrt(4)catcherror:Error->{error,Error}end.2.0
Для створення винятків, визначених користувачем, використовується функціяthrow/1, яка приймає кортеж з більш детальним описом помилки,[9] що виникла і генерує виняток класуthrow. Використання цієї функції небажане через погіршення зручності читання коду програми, але може знадобитися в деяких випадках при роботі з вкладеними структурами даних, наприклад, при розборіXML[8]. Винятки класуexit виникають у результаті виклику вбудованої функціїexit/1 або сигналу виходу.
До розробки Річардом Карлссоном (Richard Carlsson) з команди проєкту HiPE описаного вище нового механізму обробки винятків (з'явився у версії R10B) в Erlang використовувалися catch-вирази.[8]
Код програми на Erlang можна розбити на окремімодулі. Модуль — це ім'я для набору функцій, організованих в одному файлі. Ім'я модуля має збігатися з ім'ям файлу (якщо відкинутирозширення)[8]. Модуль можна відкомпілювати в байт-код як із командного рядка операційної системи, так і з командної оболонки Erlang[13]. У файлі модуля можна записати оголошення функцій тадирективи (іноді називаються атрибутами). Обов'язковим атрибутом є лише-module(атом_імені_модуля). Інший атрибут, що часто використовується —-export — застосовується для опису списку експортованих функцій, тобто функцій, які можна використовувати за межами модуля.
Функції в Erlang однозначно визначаються модулем, ім'ям таарністю. Наприклад,math:cos/1 відповідає функціїcos з модуляmath приймає один аргумент. Викликати функцію можна так:math:cos(1.2)[8]
Вихідний текст модуля компілюється в BEAM-файл — файл, що містить байт-код віртуальної машиниBEAM (англ.Bogdan’s/Björn's Erlang Abstract MachineBogdan's/Björn's Erlang Abstract Machine[23]). У свою чергу,ERTS (англ.Erlang Runtime SystemErlang Runtime System — система часу виконання Erlang) виконує цей код.[9]
Основною абстракцієюпаралельного програмування в Erlang єпроцес. Процеси можуть породжувати інші процеси, виконуватися одночасно, обмінюватися повідомленнями, реагувати на завершення один одного.
Erlang має невеликий, але потужний набір примітивів для створення процесів і спілкування між ними.
Міжпроцесовий зв'язок працює за допомогою асинхронної системи передачі повідомлень, яка не має спільного доступу: кожен процес має «поштову скриньку» — чергу повідомлень, які були надіслані іншими процесами та ще не використані. Для отримання повідомлень, які відповідають бажаним паттернам, процес використовує примітивreceive. Процедура обробки повідомлень перевіряє повідомлення по черзі на відповідність кожному паттерну, поки один з них не збігається. Коли повідомлення використано та видалено з поштової скриньки, процес відновлює виконання. Повідомлення може містити будь-яку структуру Erlang, включаючи примітиви (цілі числа, числа з плаваючою точкою, символи, атоми), кортежі, списки та функції.
Для створення нового процесу служить декілька вбудованих функцій (spawn та її аналоги)[24]. Функції повертають ідентифікатор процесу, який може використовуватися, наприклад, для надсилання повідомлень новоствореному процесу. В інтерактивній консолі erl можна отримати список процесів та іншу інформацію за допомогою функційprocesses(). таi(). відповідно.[8]
Наведений нижче приклад коду показує вбудовану підтримку розподілених процесів:
%% Створимо процес та викличемо функцію web:start_server(Port, MaxConnections)ServerProcess=spawn(web,start_server,[Port,MaxConnections]),%% Створимо віддалений процес та викличемо функцію%% web:start_server(Port, MaxConnections) на віддаленій ноді RemoteNodeRemoteProcess=spawn(RemoteNode,web,start_server,[Port,MaxConnections]),%% Відправимо повідомлення процесу ServerProcess (асинхронно).%% Повідомлення складається з кортежа з атомом "pause" та числом "10".ServerProcess!{pause,10},%% Отримаємо повідомлення, надіслані цьому процесуreceivea_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.
Як показує приклад, процеси можуть бути створені у віддалених вузлах, і взаємодія з ними є прозорою у тому сенсі, що взаємодія з віддаленими процесами працює точно так само, як взаємодія з локальними процесами.
Розподіленість (en: Concurrency) підтримує основний метод обробки помилок в Erlang. Коли процес аварійно завершується, він акуратно завершує роботу та надсилає повідомлення керуючому процесу, який потім може вжити заходів, наприклад запустити новий процес, який бере на себе завдання старого процесу.
Як і моваOccam, Erlang використовує для відправки повідомлення синтаксис зі знаком оклику:Process_ID ! Message.Прийом повідомлення — тобто вилучення його з черги («поштової скриньки») процесу — виконується за допомогою receive-виразів, які зазвичай записуються таким чином[8]:
receiveзразок1whenохорона1->вираз11,вираз12,...;зразок2whenохорона2->вираз21,вираз22,...;...зразокNwhenохоронаN->виразN1,виразN2,...;Непов'язанаЗміннаДляІншихПовідомлень->вираз1,вираз2,...end
Зустрівши такий вираз, інтерпретатор послідовно переглядає повідомлення з черги. Кожне повідомлення інтерпретатор зіставляє зі зразком і, якщо воно відповідає зразку, то обчислюються відповідні вирази. Коли всі повідомлення перебрані, і потрібного не виявилося, процес очікує нових повідомлень, після чого перебір черги повторюється. Якщо в receive-виразі відсутній зразок, якому задовольняє будь-яке повідомлення, такий вираз називається вибірковим receive-виразом.[8]
Процес можна зв'язати з іншим, у результаті між процесами встановлюєтьсядвонаправлене з'єднання (англ.link). Якщо один із процесів завершується ненормально, всім пов'язаним з ним процесам передаєтьсясигнал виходу (англ.exit signal). Процеси, що отримали сигнал, завершуються, поширюючи сигнал далі. Сигнал виходу є кортежем, елементами якого є атом'EXIT' (вихід), ідентифікатор процесу, що завершився, і причину завершення процесу. Причина завершення передається ланцюжком процесів, що завершуються.[8]
Процес може здійснитиперехоплення помилки (англ.trapping errors), якщо він має прапорець перехоплення виходу. Такий процес отримує сигнали виходу пов'язаних з ним процесів у вигляді звичайних повідомлень з аналогічною структурою кортежу. Перехоплений сигнал виходу більше не передається пов'язаним з процесом-перехоплювачем процесам. Сигнал виходу з причиною — атомомnormal (нормальне завершення процесу) не викликає завершення пов'язаного процесу. Якщо ж причина — атомkill, процес завершується беззастережно (незалежно від прапорець перехоплення виходу), а пов'язаним з ним процесам як причина відправляється атомkilled, що дає їм можливість зреагувати.[8]
Erlang має можливість встановити і однонаправлене з'єднання. При завершенні процесу, що спостерігається, процес-спостерігач отримує повідомлення із зазначенням причини завершення. Процес може зупинити себе сам чи зупинити інший процес, викликавши функціюexit.[8]
Упланувальнику процесів Erlang-системи проблемавводу-виводу, властива багатьом іншим мовам паралельного програмування, вирішена достатньо елегантно. Управління вводом-виводом, інтегроване з планувальником, вже на нижньому рівні здійснюється на основі подій, що дозволяє програмі обробляти вхідні та вихідні дані без зайвих блокувань. Такий підхід вимагає меншого числа випадків установлення та розриву з'єднань, а також прибирає необхідність блокування таперемикання контексту. Спосіб частіше застосовується в системах з явними вимогами високої доступності та низького часу відгуку. Реалізація подієво-орієнтованого вводу-виводу вбудована в Erlang-систему. Це є перевагою при проєктуванні паралельних додатків.[17]
Стандартна бібліотека містить модульio з функціями вводу-виводу. Такі функції містять в собіпобічні ефекти. Вони полягають, наприклад, у появі виведеної інформації в консолі або у записуванні даних у файл на диску. Наприклад, функціяio:format для форматованого виводу виводить рядок із підстановкою параметрів, повертаючи у разі успіху атомok.[8]
1>io:format("приклад виводу :~p~n",[1]).прикладвиводу:1ok
Функції модуляio передбачають стандартний сервернийінтерфейс вводу-виводу. Протокол вводу-виводу Erlang (англ.The Erlang I/O-protocol) детально визначає зв'язок клієнта і сервера, забезпечує двонаправлений зв'язок між клієнтами та серверами. Сервер вводу/виводу — це процес, який обробляє запити та виконує потрібне завдання, наприклад, на пристрої введення/виведення. Клієнт — це будь-який процес Erlang, який бажає читати або писати дані з/на пристрій введення/виведення.[25]
Згідно з офіційною документацією, стандартна бібліотека модулів STDLIB[14] є обов'язковою для включення до мінімальної системи Erlang/OTP[26] разом з ядром Erlang. Бібліотека містить модулі, що надають різноманітні функції для роботи з вбудованими типами та іншими структурами даних, вводу-виводу, звернення до середовища, для роботи зфайловою системою, процесами тощо.
Згідно з офіційною документацією, стандартна бібліотека модулів STDLIB є обов'язковою для включення до мінімальної системи Erlang/OTP[26] разом з ядром Erlang. Бібліотека містить модулі, що надають різноманітні функції для роботи з вбудованими типами та іншими структурами даних, вводу-виводу, звернення до середовища, для роботи з файловою системою, процесами тощо.
Модульarray :
Модульstring розширює можливості модуляlists функціями для роботи безпосередньо зі списками символів, якими є рядки в мові Erlang.
Модульdict (відангл.dictionary — словник) містить функції дляасоціативного масиву. Наприклад, збереження, вилучення та видалення значення за ключем, з'єднання масивів тощо.
Модульmath містить математичні функції.
Модульrandom містить функції для генерації псевдовипадкових чисел.
Модульcalendar забезпечує обчислення місцевого та універсального часу, дня тижня та багатьох функцій перетворення часу. Час є місцевим, коли він налаштований відповідно до поточного часового поясу та літнього часу. Час є універсальним, коли він відображає час на нульовій довготі без будь-яких поправок на літній час.
Модульtimer містить функції переведення інтервалів часу до мілісекунд, запуску подій за таймером та інші, пов'язані з часом, функції.
Модульerlang містить вбудовані функції Erlang; по замовчуванню, функції з цього модуля є імпортованими в кожен модуль.
Модульfile забезпечує інтерфейс до файлової системи. Функції для відкриття, закриття, читання та запису файлів; перегляду директорій і т. д.
Модульfilelib містить утиліти вищого рівня, ніж модульfile. Цей модуль не підтримує «необроблені» імена файлів (тобто файли, імена яких не відповідають очікуваному кодуванню). Такі файли ігноруються функціями цього модуля. Допоміжні функції для маніпуляцій з файлами:
ensure_dir(Name) -> ok | {error, Reason} — Переконується, що всі батьківські каталоги для вказаного файлу або імені каталогу існують, намагаючись створити їх, якщо необхідно. Повертає OK, якщо всі батьківські каталоги вже існують або можуть бути створені. Повертає {error, Reason}, якщо якийсь батьківський каталог не існує та не може бути створений.ensure_path(Path) -> ok | {error, Reason} — Переконується, що всі батьківські каталоги для вказаного шляху Path існують, намагаючись створити їх, якщо необхідно. На відміну від secure_dir/1, ця функція намагатиметься створити всі сегменти шляху як каталог, включаючи останній сегмент. Повертає OK, якщо всі батьківські каталоги вже існують або можуть бути створені. Повертає{error, Reason}, якщо якийсь батьківський каталог не існує та не може бути створений.Модульfilename містить функції для аналізу та обробки імен файлів. Ці функції створені таким чином, щоб код Erlang міг працювати на багатьох різних платформах із різними форматами імен файлів. Назва файлу може бути короткою відносною назвою, наприклад foo.erl, довгою абсолютною назвою, включаючи позначення диска, назвою каталогу, як-от D:\usr/local\bin\erl/lib\tools\foo.erl, або будь-якими варіаціями між ними. Допоміжні функції для маніпуляцій з файлами:
absname(Filename) -> file:filename_all() — Перетворює відносне ім'я файлу та повертає абсолютне ім'я. Не робить спроб створити найкоротшу абсолютну назву, оскільки це може дати неправильні результати у файлових системах, які дозволяють посилання.absname(Filename, Dir) -> file:filename_all() — Те саме, що absname/1, за винятком того, що каталог, до якого має бути віднесене ім'я файлу, вказано в аргументі Dir.Модульio забезпечує інтерфейс до стандартних серверів введення/виведення Erlang. Усі функції виведення повертають ОК, якщо вони успішні, або завершують роботу, якщо це не так. Функції в цьому модулі мають додатковий параметр IoDevice. Якщо він включений, це буде pid процесу, який обробляє протоколи введення/виведення. Зазвичай — IoDevice, який повертає file: open/2. Якщо IoDevice не вказано, використовується standard_io. Опис протоколів вводу-виводу є у розділі «Протокол вводу-виводу Erlang» у посібнику користувача.
Модульio_lib — функції бібліотеки введення/виведення. Містить функції для перетворення в / і з рядків (списків символів). Вони використовуються для реалізації функцій в модуліio.
Модульcrypto забезпечує набір криптографічних функцій. Наявні хеш-функції:
Модульcrypto_app — додатокcrypto. Метою програми 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 або з перелічених там сайтів-дзеркал.
Окрім цих найбільш важливих модулів, стандартна бібліотека містить багато інших, з якими можна познайомитися за документацією.[8]
Для організаціїколекцій в оперативній пам'яті в Erlang є модуль ETS (англ.Erlang Term Storage — «сховище термів Erlang»). ETS може зберігати чотири види колекцій:множина (англ.set),впорядкована множина (англ.ordered set),мультимножина (англ.bag),мультимножина з повтореннями (англ.duplicate bag).[9] Доступ до елементів колекцій відбувається ключовим полем кортежу(ключі, як і значення, можуть бути будь-яких типів). Упорядковані множини зреалізовані у вигляді бінарних збалансованихАВЛ-дерев, а інші колекції — з використаннямхеш-таблиць.[8]
DETS-таблиці доповнюють функціональність ETS-таблиць (за винятком впорядкованих множин), дозволяючи зберігати дані у файлах.

OTP (англ.Open Telecom Platform) є налагодженим набором корисних поведінок (англ.behaviours) процесів. Він використовується для створення серверних програм. OTP формалізує дії процесів та дозволяє будувати на їх основіOTP-додатки. Умодулях ОТР визначено загальні, стандартизовані шаблони для конструювання паралельних додатків.Gen_server — інтерфейсний модуль для реалізації клієнт-серверної архітектури.[27] Загальний серверний процес (gen_server), реалізований за допомогою цього модуля, має стандартний набір інтерфейсних функцій і включає функції відстеження та звітування про помилки. Він вписується в дерево нагляду OTP. Найпопулярнішими поведінками є узагальнений сервер та спостерігач (англ.supervisor)[28]. Є й інші поведінки:кінцевий автомат, обробникподій[29].[9] OTP містить і іншесполучне програмне забезпечення (англ.middleware), наприклад,СУБДMnesia.
OTP-поведінки поділяються на робочі процеси (англ.worker processes):
У завдання процесів спостерігачів входить стеження за робочими процесами та іншими процесами спостерігачами — нащадками. Дерева спостерігачів складають OTP-додаток (англ.application). Документація Erlang визначає OTP-додаток компонентом, який реалізує деяку функціональність, яка може бути незалежно запущена на виконання і зупинена як ціле, а такожповторно використана в інших системах.[30] Розробник програми пише кодмодулів функцій зворотного виклику (англ.call-back module), в яких і знаходиться специфічна для цієї програми частина функціональності.[8]
Строго кажучи, OTP не є частиною мови Erlang. Однак, він настільки увійшов у культуру та практику розробників на Erlang, що часом між ними складно провести межу.[9]
Розробка додатків зграфічним інтерфейсом користувача (крімвеб-інтерфейсів) може вестись за допомогою бібліотеки wxErlang — бібліотекиwxWidgets, портованої для Erlang. В стандартну поставку Erlang/OTP входить WxErlang. WxWidgets написаний наC++, тому перед розробниками wxErlang стояло завдання виразити засобами Erlang ієрархіюоб'єктів. Спрощуючи, у wxErlangкласам відповідають модулі, а об'єктам — посилання, макросам на C ++ відповідають макроси Erlang. Деякі типи даних, для яких у C++ були використані класи, подаються в Erlang за допомогою інших типів даних, наприклад wxPoint задається у вигляді кортежу з двох елементів. Події wxErlang можна оброблити в Erlang або через функцію зворотнього виклику (англ.call-back functions), або в більш природному середовищі Erlang передачею повідомлень.[8]

Інтерактивна оболонка (англ.shell) для Erlang може бути викликана вUnix-подібних системах командоюerl, у Windows —werl.
Оболонка дозволяє:
Також, оболонка дозволяє використовувати додаткові функції (команди), доступні тільки в ній. До прикладу, командаq(). здійснює вихід із оболонки із завершенням всього, що робить Erlang-система.[17]
В оболонці можна викликати BREAK-меню за допомогоюCtrl+C (у Unix-подібних ОС) абоCtrl+Break (у Windows). Це меню має різні команди, у тому числіa — негайна зупинка,c — продовження роботи в оболонці та інші інформаційні та допоміжні команди для роботи з Erlang-системою. Комбінація клавішCtrl+G викликає ще командне меню, яким можна, за необхідності, зупинити процес, що «завісив» оболонку, і повернутися в оболонку (i і потімc)[13]
Система EDoc може генерувати документацію з вихідного коду. Для документування коду модуля достатньо додати певним чином розмічений текст, а також файлoverview.edoc для документації рівня проєкту (в останньому необов'язково використовувати знаки коментаря)[9]. Інструменти для роботи з кодом на Erlang, наприклад, erlang-режим вEmacs, мають на увазі деякі особливості щодо вживання символів коментаря. Коментарем вважається текст від знака відсотка (%) до кінця рядка в Erlang. Так, потрійний знак відсотка викликає вирівнювання лівим краєм, подвоєний — вирівнювання на рівні навколишнього коду, а одиночний знак відсотка використовується для позначення коментаря після коду, в кінці рядка[9]. Розробники Erlang виробили певністильові угоди щодо організації та оформлення вихідного коду. Наприклад, хорошим стилем вважається зниження вкладеності синтаксичних структур, написання коротких модулів (менше 400 рядків коду) та функцій (не довше 15-20 рядків коду), використання осмислених імен для змінних та функцій тощо.[31]
Програма Dialyzer, розроблена в рамках проєкту HiPE. Вона входить до стандартної поставки і дозволяє виявити помилки (у тому числі помилки типізації) шляхомстатичного аналізу коду. Програма TypEr, написана Тобіасом Ліндалом (Tobias Lindahl) та Костісом Сагонасом (Kostis Sagonas), є частиною Dialyzer. TypEr дозволяє перевіряти визначення типів функцій, звіряти вказаний у директиві-spec тип функції з її визначенням, виконати виведення типів. Програма виводить всі типи, що відповідають успішному застосуванню функції, в загальному випадку лише приблизно, в більш грубий бік. Використання функції будь-яким іншим чином обов'язково призведе до помилки часу виконання. У наступному прикладі показаний синтаксис визначення типу (директива-type), оголошення типу полів запису та директива-spec разом з визначенням функції[8]:
-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)->% визначення функції...
Dialyzer (відангл.DIscrepancy AnaLYZer for ERlang Programs — «аналізатор суперечностей для Erlang-програм») програма для виявлення в коді окремих модулів і в окремих додатках, помилок типів,недосяжного коду та надлишкових перевірок. Усі виявлені Dialyzer дефекти вимагають усунення, бо інструмент не дає помилкових спрацьовувань. Для кожної функції всіх модулів, що перевіряються, Dialyzer, встановлює тип, використовуючи заснований на обмеженнях вивід типів і аналіз потоків даних. Після визначення типів функцій проводиться аналіз протиріч у програмі.[32]
Длямодульного тестування Erlang надає EUnit. Длясистемного тестування Erlang надає фреймворк Common Test. EUnit містить засоби для опису тестів, в тому числі необхідний для цього набір макросів, а також виводить звіт по закінченню тестування. Тестування модулів відбувається шляхом підключення заголовного файлу з EUnit, а функції з тестами можуть бути як включені в сам модуль, що тестується, так і винесені в окремий модуль.[8]
Тестування паралельних програм можна виконати за допомогою Quviq Quick Check (версія Mini безкоштовно). Крім тестування, можна здійснити перевірку всіх можливих варіантів вихідних даних за допомогою методуперевірки моделей. Для цього є, створена в Мадридському політехнічному університеті, утиліта McErlang.[1][8]
Щобпрофілювати код та виявити ступіньпокриття коду тестами можна звернутися до модулівeprof,fprof,cover таутиліти cprof.[9]
Для Erlang розроблена низка інструментіврефакторингу вихідного коду (список не є вичерпним):
Утиліта tidier дозволяє автоматично знаходити та виробляти еквівалентні перетворення коду, наприклад, замінює
lists:filter(fun(X)->is_something(X)end,L)
на
[X||X<-L,is_something(X)]
Erlang має свої секрети написання ефективного коду. Удосконалення мови робить деякі з трюків застарілими, тому документація є найкращим посібником у питаннях оптимізації, у сукупності з профілюванням тастрес-тестуванням.
Наприклад, при роботі зі списками не бажано додавати елемент до кінця довгого списку за допомогою конкатенації або функції додавання елемента до списку. Зате можна додати елемент до початку списку, а кінцевий результат обробити функцією звернення порядку елементів списку.
L1=[New_Elem|List].L2=lists:reverse(L1).
Є свої рекомендації і для підвищення ефективності паралельних програм. До прикладу, дії, що вимагають багато пам'яті, найкраще виділяти в окремий процес, бо при цьому зменшуються витрати на збирання сміття. Тоді пам'ять швидше буде звільнено після завершення процесу.[8]
Erlang-система дозволяє виконувати інтеграцію з системами на інших мовах програмування. Є механізми для мережевої взаємодії зС,Java,Лісп,Perl,Python,Ruby. До прикладу, для ефективнішого синхронного виклику невеликих функцій на C можна використовувати платформно-залежні функції (англ.NIF, natively implemented function). Високорівневі бібліотеки дозволяють Erlang-системі представляти C або Java-вузли як звичайні Erlang-вузли. Інші мови можна пов'язати з середовищем виконання Erlang за допомогоюдрайверів або мережевихсокетів за допомогою протоколів на кшталтHTTP,SNMP, IIOP. До прикладу, Ruby взаємодіє з Erlang за допомогою пакета erlectricity, а для Python розроблена реалізація Erlang-вузла у вигляді пакету py-interface.[20]
Віртуальна машина Erlang знаходить застосування і в інших мовах програмування. До прикладу,Elixir та проєкт Erl2 Джо Армстронга. Крім того, Роберт Вірдінг підтримує проєкт Lisp Flavored Erlang («Erlang, приправлений Ліспом»), у якому синтаксисЛіспа використовується з компілятором[34] Erlang. Є й інші BEAM-мови: Efene, Joxa, Reia[35], Luerl, Erlog[36].
На офіційному сайті мови єзгадка проєкт проErjang, в якому використовується віртуальна машина Java.
Практика показує, що для вивчених телекомунікаційних додатків код на Erlang був на 70—85 % коротшим, ніж наC++, а продуктивність системи при переписуванні коду з C++ на Erlang зросла майже на 100 %[37]. Для одного із використаних у дослідженні проєктів різниця була пояснена написанням додаткового C++ коду в рамкахзахисного програмування, управління пам'яттю та коду для високорівневої комунікації, тобто можливостями, які є частиною мови Erlang та бібліотек OTP.[8]
Впливтеорії послідовних процесів, що взаємодіють,Чарльза Е.Хоара відчувається як уGo, так і в Erlang.
Erlang і Go
Спільне : процеси відправляють одне одному повідомлення.
Відмінне:
Організація взаємодії з повідомленнями
У Erlang немає типізації часукомпіляції за винятком охоронних виразів, що дозволяє посилати процесам повідомлення будь-якого типу. «Незрозуміле» повідомлення буде проігноровано, або назавжди залишиться в черзі[38].
Go дозволяє легко організувати групу «go-програм» (англ.goroutine — натяк наангл.co-routine —співпрограма) для отримання повідомлень з деякого каналу (такий підхід відомий якпул потоків).
Реалізація робочого пулу
В Erlang, при проєктуванні якого приділялася особлива увагадетермінізму та часу затримки (англ.latency), реалізація робочого пулу можлива, але потребує додаткових зусиль. Численні відправники тривіально реалізуються в обох мовах.[38] Erlang-процес може надіслати повідомлення і чекати на нього відповідь (відповідно до деякого зразка), ігноруючи інші повідомлення в черзі.
В Go таке неможливо, але подібна функціональність може бути досягнута створенням (у тому числі динамічним) нових вводів, тобто поділом каналів за призначенням.[38]
Розділення між процесами
В Erlang відсутній стан, що розділяється між процесами (англ.shared mutable state) і тому ізольований процес дуже рідко представляє інтерес[38]
Go вимагає явної вказівки того, які go-програми будуть взаємодіяти з іншими передачею повідомлень.
Абстракції взаємодіючих процесів схожі в Erlang і Go. Щоб уникнути помилок при переході з однієї мови на іншу, слід враховувати тонкощі і особливості обох мов: шаблони, які хороші в одній мові, можуть не підходити для іншої.[38]
В Erlang є недоліки[40]:
. , або;). Це вимагає додаткової уваги при зміні місця виразу.Джо Армстронг, один з творців мови, у своєму виступі на конференції з історії мов програмування в 2007 році перерахував список зон зростання для мови:[41]
Масове поширення Erlang може стримувати незвичний для більшості програмістівсинтаксис, використанняфункціональної парадигми, а також те, що найкраща на 2022 рік реалізація мови використовує віртуальну машину BEAM, а не більш поширенуJVM.[42]

Erlang підходить для:
Erlang погано підходить для: Написання коду, що містить інтенсивні обчислення з плаваючою комою, який вимагає включеннянативного коду конкретної платформи чи сильної оптимізації і для створення додатків, які потребують синхронного виконання завдань.
Для проєктів, в яких код повинен виконуватися наJVM абоCLR, або проєктів, що вимагають безлічі бібліотек з інших систем програмування[44].
Крім того, Erlang став застосовуватися для :
Erlang часто ставлять у заслугу легендарну надійність ATM-комутатора AXD301 у мережіBritish Telecom.
За даними Ericsson, з січня 2002 року за декілька років трапилася лише одна незначна несправність, на підставі чого надійність системи згідно з розрахунками була 99,9999999 %[49]. Хоча більш реальні оцінки, що враховують багато інших факторів, говорять все-таки про «п'ять дев'яток», успіх маршрутизатора пов'язують з доступними засобами розробки надійних паралельних обчислень, вбудованими в Erlang[49].
Ще Erlang використовується в додаткахз відкритим вихідним кодом, наприклад:
Для Erlang було написано декількавеб-серверів:
Ще були створені декількавеб-фреймворків ісистем управління вмістом, таких як:
Серед відомого програмного забезпечення, написаного Erlang, яке не увійшло в категорії вище виділяють:
Крім того, написаний на Erlang інструментTsung, який дозволяє емулювати тисячі (за достатньої кількості тестових серверів — мільйони) одночасних користувачів, застосовується у стрес-тестуваннях розподілених систем[61].
Erlang підходить для завданьштучного інтелекту (особливообчислювального інтелекту,нейроеволюції), заснованих нанейронних мережах. Таке застосування можливе завдяки п'ятьом ключовими властивостями «мови програмування нейронних мереж», що є у Erlang:
Прикладом такого застосування є реалізація одного з підходів до нейроеволюції — DXNN[62].
Навколо технологій Erlang утворилась спільнота розробників, яка підтримує новачків.
Вихідний код Erlang доступний через сервіс спільної розробкиGitHub. Розробники та користувачі Erlang можуть спілкуватися через список розсилки Erlang-questions (питання Erlang) або на IRC-каналі #erlang наFreenode.
Erlang Factory влаштовує у всьому світі заходи та конференції, серед яких конференція користувачів Erlang (Erlang User Conference).
Спеціальна група SIGPLANACM регулярно проводить Erlang-майстерню (Erlang Workshop), а конференціяOSCON включає секцію з Erlang[63].
В УкраїніErlang спільнота порівняно невелика.
{{cite book}}:Перевірте значення|isbn=: недійсний символ (довідка){{cite book}}:Перевірте значення|isbn=: недійсний символ (довідка){{cite web}}:|archive-url= вимагає|archive-date= (довідка)[Архівовано 2011-10-25 уWayback Machine.]{{cite book}}:Перевірте значення|isbn=: недійсний символ (довідка){{cite book}}:|pages= має зайвий текст (довідка);Перевірте значення|isbn=: недійсний символ (довідка){{cite book}}:Зовнішнє посилання в|deadurl= (довідка);Недійсний|deadurl=https://dl.acm.org/doi/10.1145/1596600.1596602 (довідка)Обслуговування CS1: Сторінки з посиланнями на джерела із зайвою пунктуацією (посилання){{cite web}}:Зовнішнє посилання в|last= (довідка)| Це незавершена стаття промови програмування. Ви можетедопомогти проєкту,виправивши або дописавши її. |