avatar

Пара слов об Erlang

опубликовал в Программирование
Вступление

В комментариях к статье «Немного о сетевом движке на Erlang» меня спросили, что хорошего в этом языке и почему я выбрал его. В этом коротком очерке я постараюсь ответить на эти вопросы.

Установка

Установка Erlang очень простая. Надо перейти на сайт Erlang Solutions, выбрать версию (текущая версия R16B01) и операционную систему. Дальше все по обычной схеме «далее-далее-далее-финиш».

Есть, конечно, более интересный способ. Это установка из исходных кодов. Скачиваем исходники с официального сайта и следуем инструкции.

Арифметика

В Erlang не надо заботиться о размере чисел. Если сложить 2 + 3, то получим число размером 1 байт. Если складывать более большие числа, то получим значение int32 или даже int64.

1> 2 + 3.
5
2> 234234653645263572354264572364 + 273645275472653476234572534762354723645.
273645275706888129879836107116619296009

Поэтому вам можно не беспокоиться «какой же выбрать тип переменной, чтобы и памяти меньше уходило и чтобы переполнения не было». Erlang все сделает за вас.

Замечание: Строчки, начинающееся с 1>, 2> означают, что это команды, введенные в консоли. Обратите внимание, что все выражения должны заканчиваться точкой.

Конечно же, кроме сложения есть все необходимые арифметические операции. Вычитание (-), умножение (*), деление (/), целочисленное деление (div) и остаток от деления (rem).

3> 5 - 1.
4
4> 10 * 4.
40
5> 5 / 2.
2.5
6> 5 div 2.
2
7> 5 rem 2.
1

Для изменения порядка операций можно использовать скобки.

А что, если надо использовать числа не в десятеричной системе счисления? Все очень просто. В Erlang есть замечательная вещь, которая позволяет выполнять действия над числами с основанием от 2 до 36. Она имеет вид Основание#Значение. Т.е. запись 2#101 будет означать число 101 в двоичной системе счисления (это 5 в десятичной).

8> 2#101010.
42
9> 8#0677.
447
10> 16#FF.
255
11> 16#FF - 16#F0.
15

Неизменяемые переменные

Пожалуй самое мозгодробительное для программистом C++, C# и других императивных языков это то, что в Erlang значения переменных нельзя изменять. Когда я первый раз об этом узнал, то сразу возникла мысль «как можно программировать, если нельзя изменять переменные? Что за бред?». Спокойствие. Только спокойствие. На самом деле, все просто. Главное запомните, что переменные должны начинаться с большой буквы.

1> One = 1.
1
2> Two = One + One.
2
3> Two = 2.
2
4> Two = 3.
** exception error: no match of right hand side value 3

Почему выполнение четвертого выражения вызвало ошибку? На второй строчке переменной Two было присвоено значение 2. На третьей строчке фактически находится выражение 2 = 2. А на четвертой 2 = 3. Но мы еще со школьных времен знаем, что 2 не может равняться 3. Erlang в этом плане на много ближе к обычной математике, чем другие языки. Ведь при решении уравнений мы не могли написать

X = 10

а через несколько строк

X = 20

За это вы бы точно получили двойку. Ведь нас учат, что переменная не может изменять своего значения. При решении квадратных уравнений мы получали две переменные X1 и X2, но никак не одну X, которая одновременно равняется двум числам.

Так же существует специальная переменная _ (нижнее подчеркивание). Для простоты можно считать, что она может принимать любые значения.

5> _ = 10.
10
6> _ = 15.
15

Атомы, кортежи и списки

Можно считать атомы строковыми константами. Они должны начинаться с маленькой буквы.

Кортеж (tuple) — это способ организации данных. Он имеет синтаксис {Элемент1, Элемент2, ..., ЭлементN}. Например, можно создать кортеж из двух атомов {fruit, apple} или кортеж, обозначающий точку {point, X, Y}. Элемент кортежа может быть любым типом данных.

Списки можно рассматривать как массив, который может содержать любые элементы. Он имеет синтаксис [Элемент1, Элемент2, ..., ЭлементN]. Например, это список, описывающий разные фрукты [{fruit, apple}, {fruit, bannan}, {fruit, strawberry}]. Списки могут быть пустыми [].

Все списки состоят из головы (head) и хвоста (tail). Голова — это всегда первый элемент списка, а хвост — все остальное. Голова отделяется от хвоста с помощью вертикальной черты |.

1> [Head | Tail] = [{fruit, apple}, {fruit, bannan}, {fruit, strawberry}].
[{fruit,apple},{fruit,bannan},{fruit,strawberry}]
2> Head.
{fruit,apple}
3> Tail.
[{fruit,bannan},{fruit,strawberry}]
4> [Fruit1, Fruit2 | Rest] = [{fruit, apple}, {fruit, bannan}, {fruit, strawberry}].
[{fruit,apple},{fruit,bannan},{fruit,strawberry}]
5> Fruit1.
{fruit,apple}
6> Fruit2.
{fruit,bannan}
7> Rest.
[{fruit,strawberry}]
8> [Fruit1, Fruit2, Fruit3 | MoreFruits] = [{fruit, apple}, {fruit, bannan}, {fruit, strawberry}].
[{fruit,apple},{fruit,bannan},{fruit,strawberry}]
9> Fruit3.
{fruit,strawberry}
10> MoreFruits.
[]

Обратите внимание, что Head — это элемент списка. Тогда как Tail — это список.

11001000...

Битовый синтаксис потрясающая вещь. По своим свойствам она очень напоминает списки. У нее так же есть голова и хвост. Единственное отличие — элемент bit syntax это байт. Т.е. bit syntax можно считать усовершенствованным списком для работы с байтами (и битами).

1> Bytes = < < 23, 34, 234, 12 > >.
< < 23,34,234,12 > >
2> < < R, G, B > > = < < 10, 20, 30 > >.
< < 10,20,30 > >
3> Color = 16#F09A29.
15768105
4> Pixel = < < Color:24 > >.
< < 240,154,41 > >
5> Pixels = < < 213,45,132,64,76,32,76,0,0,234,32,15 > >.
< < 213,45,132,64,76,32,76,0,0,234,32,15 > >
6> < < Pix1:24, Pix2:24, Pix3:24, Pix4:24 > > = Pixels.
< < 213,45,132,64,76,32,76,0,0,234,32,15 > >
7> < < R2:8, G2:8, B2:8 > > = < < Pix1:24 > >.
< < 213,45,132 > >
8> R2.
213
9> < < R2:8, Rest/binary > > = Pixels.
< < 213,45,132,64,76,32,76,0,0,234,32,15 > >
10> R2.
213

Из-за того, что неверно отображаются данные внутри тега code, поставлю пробелы между символами < < и > >.

Круто! Не правда ли? :) Кстати после двоеточия указывается размер значения в битах.

Вот так, например, можно распарсить TCP пакет.

< < SourcePort:16, DestinationPort:16,
AckNumber:32,
DataOffset:4, _Reserved:4, Flags:8, WindowSize:16,
CheckSum: 16, UrgentPointer:16,
Payload/binary > > = SomeBinary.

Более подробно про все, что здесь было написано, можно почитать тут.

Процессы

Сперва я хотел описать подробно что такое процессы, OTP, зачем все это использовать. Но понял, что не смогу описать все очень просто и подробно. Не из-за того, что это сложная тема, а из-за того, что у меня мало опыта в таких делах :) Поэтому расскажу как смогу, кратко, сжато. А в конце дам ссылки где все это можно изучить подробнее.

Процессы — это основа Erlang. Он может запустить миллионы легковесных процессов, которые будут выполняться параллельно. Между собой они общаются путем посылки сообщений. Общих данных у них нет, поэтому никаких блокировок и порчи данных. Если подключить дополнительную ноду (сервер) к кластеру, то он начнет автоматически использоваться. Т.е. не надо думать (почти) как разработать ПО, чтобы оно было легко масштабируемым.

В Erlang исповедуется философия Let it crash. Т.е. если в некотором процессе произошла ошибка, то пусть он упадет. Перезапустить его на столько просто и быстро, что реализовывать логику по отлову всех возможных ошибок смысла нет.

Подводя итог, чем же мне понравился этот язык:
  • легкая масштабируемость
  • высокая отказоустойчивость
  • мощные механизмы работы с данными (в частности bit syntax)

В общем, получилась вот такая сжатая и сумбурная статья. Если что-то непонятно, то смело задавайте вопросы в комментариях.

Литература для чтения

Programming Erlang: Software for a Concurrent World
Erlang and OTP in Action
Learn You Some Erlang for great good!
+2
0
587
  • 5 комментариев

    avatar
    Erlang в этом плане на много ближе к обычной математике, чем другие языки. Ведь при решении уравнений мы не могли написать

    X = 10

    а через несколько строк

    X = 20

    За это вы бы точно получили двойку. Ведь нас учат, что переменная не может изменять своего значения.

    В эрланге это сделано ради безопасности, чтобы один поток никаким образом не смог изменить значение переменно другого потока. Ну вы привели свое суждение о данной особенности языка)
    avatar
    Вы правы, что это сделано ради безопасности. Кстати неизменямые переменные есть и в других функциональных языках.

    Пример про уравнения приводит Армстронг (создатель языка) в своей книге Programming Erlang: Software for a Concurrent World. Этот пример мне очень понравился, поэтому решил использовать сравнение с уравнениями в статье :)
    avatar
    Не люблю функциональщину, поэтому насчет других вообще не в курсе) Ну пример действительно наглядный, не читал книгу) То есть это ваш перевод?
    avatar
    То есть это ваш перевод?
    Статья написана по мотивам этой главы сайта learnyousomeerlang.com. Но в ней опущено очень и очень многое.

    Не хотел писать подробный туториал по языку. Просто вводную часть, чтобы помочь людям чуточку лучше понимать его. Вдруг где-то в интернете попадется код на Erlang и надо будет хотя бы поверхностно понять что он делает :)
    avatar
    Хорошее дело затеяли)
    Чтобы оставить комментарий необходимо .