Основы Erlang: синтаксис и пунктуация

Мои теоретичесие рассуждения о месте 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'ах, да и просто погуглив.

www.insight-it.ru/programmirovanie/erlang/osnovy-erlang-sintaksis-i-punktuaciya/

Вверх