Мои теоретичесие рассуждения о месте Erlang в современном мире Интернете Вы можете почитать в отдельной статье. Если сомневаетесь интересно Вам это все или нет - то прочтите сначала её. Сегодня я постараюсь вернуться с небес на землю и пройтись по азам этого пугающего многих языка программирования. Коротко и по делу.
Установка ничем особым не выделяется, дистрибутив рекомендую брать отсюда, если до сих пор пользуетесь отсутствующей в списке ОС - лучше сначала исправить этот факт.
После установки в $PATH
окажутся исполняемые файлы:
- erl - одновременно интерактивная консоль и запуск приложений;
- erlc - компилятор в байт-код для виртуальной машины BEAM или нативный код посредством HiPE, напрямую использовать не придется практически.
Со всем что будет обсуждаться в этой статье можно эксперементировать просто в интерактивной консоли, которая запускается просто командой erl без аргументов.
Пунктуация
Сразу скажу, что пунктуация в Erlang довольно своеобразна, больше похожа на русский язык, чем на другие языки программирования. По крайней мере я именно этой ассоциацией пользовался, когда запоминал.
- Все функции заканчиваются точкой
- После каждого выражения в функции - запятая;
- Все ветви кода
(case, if, ...)
, кроме последней, заканчиваются точкой с запятой - После заголовка функции и условий ветвления пишется стрелка
->
Маленькая демонстрация:
foo(X, Y) ->
Z = X * X,
if
Y > 0 ->
Z + Y;
true ->
Z - Y
end.
К слову, функции возвращают результат выполнения последнего выражения, в данном случае оно представляет собой весь блок if
, а end
обозначает его окончание (не функции).
Синтаксис
Foo
- все что начинается с английской заглавной буквы - переменная, специально объявлять ничего не нужно_
- сам знак нижнего подчеркивания и все что с него начинается - особый случай переменной, значение которой не значимо для программы и при первой возможности "выкидывается"- Цифры в основном как обычно, есть научная нотация в духе
1.23e4
(1.23 умножить на 10 в степени 4) и системы исчисления с другим основанием, скажем двоичная -2#101010
foo
- с строчной буквы начинаются атомы, по сути константы, используются повсеместно:- названия функций и модулей
true
иfalse
- булевые значенияok
- типичный результат успешный результат выполнения
?FOO
- хоть официально и называются константами, но по сути - макросы, перед компиляцией заменяются на заранее определенный кусок кода{foo, bar}
- кортеж, набор данных фиксированной длины[foo, bar]
- простой однонаправленный список произвольной длины"foo"
- текстовая строка, представленная в виде однонаправленного списка (что не эффективно с точки зрения потребления памяти, до 4 байт на символ)<<"foo">>
- бинарная строка, может содержать что угодно, в.т.ч. и текст; все что не цифры по возможности лучше хранить в этом типе данных.
Сопоставление (pattern matching)
Очень мощная концепция сопоставления используется в Erlang на каждом углу. В базовом варианте работает примерно так:
{ok, Result} = foo().
Если в функции foo все прошло нормально, то она возвращает, например {ok, 123}
, и переменной Result
окажется лишь значение 123
.
Если же возникла какая-то проблема, то она вернет что-то другое, скажем {error, timeout}
, приложение столкнется с несоответствием левой и правой части (атомы ok и error разные) и прекращает свое выполнение (если бы было чего выполнять).
Базовый принцип, надеюсь, понятен. Подобным образом выбирается какую из реализаций функции использовать, в какую ветвь case идти и т.п. В общем есть много других более сложных применений, но о них в другой раз.
Списки
Со списками есть три особые операции:
[Head | Tail ] = [1, 2, 3, 4]
- вытащить элемент с головы списка, работает по принципу сопоставления, вHead
окажется1
, а вTail
-[2, 3, 4]
[1, 2] ++ [3, 4]
- конкатенация, результатом будет[1, 2, 3, 4]
[N * N || N <- [1, 2, 3], N > 1]
- выглядит замороченно, по сути это обычный отображение (map) с фильтрацией (filter) - то есть выражение перед||
применяется к каждому элементу списка, значение которых попадает в переменную N, а после запятой - условие, накладываемое на N; таким образом результат будет [4, 9]
Бинарные строки
C ними намного больше всяких трюков и преобразований, приведу наиболее значимые:
Binary = <<Integer:64>>
- преобразовать целое число Integer в бинарную строку Binary длиной 64 бита (для примера, может быть любой<<Integer1:32, Integer2:32>> = Binary
- распокавать обратно бинарную строку в целые числа, но уже два по 32 бита; чем-то похоже на операцию[H | T]
у списков, но намного более гибкоBinary3 = <<Binary1/binary, Binary2/binary>>
- конкатенация бинарных строк, результат окажется вBinary3
<<<<(N * N)/integer>> || <<N>><= <<1, 2, 3>>, N > 1 >>
- аналог последнего примера для списков, только для бинарных данных; результат аналогичен -<<4, 9>>
; к слову официально это называется binary comprehensions, а для списков - list comprehensions
Заключение
Очень многое пришлось опустить, иначе самое главное затерялось бы, да и объем статьи сильно вырос. Подробности всегда можно найти на официальном сайте, в man'ах, да и просто погуглив.
Удачного освоения Erlang!