Установка, оболочка erl и первая программа

С чего начать практику: ставим Erlang и пробуем оболочку.

erl — интерактивная оболочка (REPL) Erlang, где можно вычислять выражения и проверять идеи без компиляции файлов.

Erlang распространяется как комплект Erlang/OTP — сам язык вместе со стандартными библиотеками OTP. Это важная деталь: вы почти никогда не ставите «голый» язык, вы ставите целую платформу с готовыми инструментами для построения надёжных систем. Установка зависит от системы: на macOS обычно ставят через Homebrew, на Linux — через пакетный менеджер или официальный установщик, на Windows есть готовый инсталлятор. Удобный кросс-платформенный способ — менеджер версий вроде asdf или kerl.

Почему стоит задуматься о менеджере версий с самого начала? Разные проекты нередко требуют разных версий Erlang/OTP, а системный пакет даёт лишь одну, ту, что есть в репозитории дистрибутива, — и она часто заметно устаревшая. Менеджер версий позволяет держать несколько сборок Erlang рядом и переключаться между ними одной командой, не ломая систему. Для учебных целей подойдёт и пакет из системного менеджера, но если вы планируете работать всерьёз, привычка управлять версиями избавит вас от множества будущих проблем с несовместимостью.

# macOS
brew install erlang

# Ubuntu/Debian
sudo apt-get install erlang

# Проверка версии
erl -version

Первое знакомство с оболочкой

Запустите команду erl — откроется приглашение. Оболочка (её называют REPL — read-eval-print loop) — это ваш главный инструмент в первые недели изучения языка. Здесь не нужно создавать файлы, компилировать, запускать: вы просто пишете выражение, нажимаете Enter и сразу видите результат. Это идеальная песочница, чтобы проверить, как работает та или иная функция, какой тип у значения, что вернёт незнакомая конструкция. Опытные эрлангисты держат оболочку открытой постоянно и проверяют в ней гипотезы, даже работая над большим проектом.

Здесь можно вычислять выражения. Важная деталь: каждое выражение в оболочке завершается точкой, иначе оболочка ждёт продолжения. Это типичная ловушка новичка: вы пишете 2 + 2, жмёте Enter, а оболочка молчит и показывает приглашение к продолжению ввода. Ничего не сломалось — она просто ждёт точку, которая означает «выражение закончено, можно вычислять».

1> 2 + 2.
4
2> "Привет".
"Привет"
3> X = 10.
10
4> X * 5.
50

Обратите внимание на пронумерованные приглашения вида «1>», «2>» — это номера команд, по ним удобно ссылаться на прежний ввод. В четвёртой строке примера мы использовали переменную X, заданную в третьей: оболочка помнит связанные переменные в пределах сессии. Выйти из оболочки можно командой q(). или сочетанием Ctrl+C дважды. Полезные оболочечные команды: c(Module). компилирует и загружает модуль, f(). «забывает» переменные, h(). показывает историю. Команда f() особенно пригодится, когда вы захотите переиспользовать имя переменной: поскольку переменные в Erlang связываются один раз, «забыть» старое значение — единственный способ задать его заново в той же сессии.

Структура модуля

Настоящие программы живут в модулях — файлах с расширением .erl. Оболочка хороша для экспериментов, но всё, что вы хотите сохранить и переиспользовать, оформляется как модуль. Модуль — это и единица кода, и единица компиляции, и пространство имён: функции одного модуля не конфликтуют с одноимёнными функциями другого. Минимальный модуль состоит из трёх частей: объявление имени, экспорт функций и сами функции.

% файл math_utils.erl
-module(math_utils).
-export([square/1, cube/1]).

square(X) ->
    X * X.

cube(X) ->
    X * X * X.

Запись square/1 означает «функция square, принимающая 1 аргумент». Число после слэша — это арность (количество аргументов). В Erlang функции с одинаковым именем, но разной арностью — это разные функции. Для новичка это непривычно: add/2 и add/3 — две совершенно независимые функции, которые могут делать что угодно, и компилятор их не путает. Поэтому, говоря о функции в Erlang, всегда называют её вместе с арностью: не просто «square», а «square дробь один». Это часть культуры языка, и в документации, и в сообщениях об ошибках вы будете видеть именно такую запись.

Строка -export заслуживает отдельного слова. Всё, что в неё не попало, остаётся приватным — видимым только внутри модуля. Это встроенный механизм инкапсуляции: вы явно проводите границу между публичным интерфейсом модуля и его внутренней кухней. Хорошая привычка — экспортировать как можно меньше, оставляя снаружи лишь те функции, которыми действительно должны пользоваться другие модули. Тогда внутреннее устройство можно свободно менять, не боясь сломать чужой код.

Компиляция и запуск

1> c(math_utils).
{ok,math_utils}
2> math_utils:square(7).
49
3> math_utils:cube(3).
27

Обращение к функции из модуля записывается как Модуль:функция(Аргументы) — это называют квалифицированным вызовом. Внутри самого модуля свои функции можно звать без префикса. Имя модуля обязательно должно совпадать с именем файла: модуль math_utils обязан лежать в файле math_utils.erl. Это жёсткое правило, а не рекомендация, и нарушив его, вы получите ошибку компиляции.

Как работает под капотом

Команда c(math_utils) вызывает компилятор, который превращает .erl в файл .beam с байт-кодом и сразу загружает его в работающую систему. Это значит, что вы можете менять код и перезагружать модуль не останавливая оболочку — основа горячей замены кода, к которой мы вернёмся в конце курса.

Эта способность подменять код в работающей системе — одно из самых необычных свойств Erlang, и оно прямо вытекает из телеком-корней языка. Телефонную станцию нельзя остановить, чтобы обновить её программу, — звонки идут круглосуточно. Поэтому в BEAM встроена возможность загружать новую версию модуля прямо поверх старой: уже выполняющиеся вызовы доработают на прежнем коде, а новые пойдут по обновлённому. Пока вы учитесь, вы будете пользоваться этим в малом масштабе — поправили функцию, набрали c(модуль), тут же проверили результат, не перезапуская оболочку. Этот короткий цикл «правка — перекомпиляция — проверка» делает обучение Erlang на удивление живым и интерактивным.

Частые ошибки

  • Забыть точку в конце выражения в оболочке. Оболочка будет молча ждать продолжения — допишите точку и Enter.
  • Назвать файл не так, как модуль. Компилятор откажется: имя модуля и файла должны совпадать.
  • Не экспортировать функцию. Снаружи её вызвать не получится — добавьте в -export.

Итоги

  • Erlang ставится как комплект Erlang/OTP; erl — это REPL.
  • В оболочке выражения завершаются точкой; переменные присваиваются через =.
  • Модуль = имя + экспорт + функции; имя файла совпадает с именем модуля.
  • Функция вызывается как module:function(args); name/arity задаёт сигнатуру.
Проверьте себя
1. Чем завершается выражение в оболочке erl?
AТочкой с запятой
BТочкой
CПустой строкой
DСловом end
2. Что означает запись square/1 в строке -export?
AФункцию square версии 1
BФункцию square с арностью 1 (один аргумент)
CДеление square на 1
DПервую строку функции
3. Каким должно быть имя файла модуля math_utils?
AЛюбым
Bmath.erl
Cmath_utils.erl — совпадать с именем модуля
Dmodule.erl