Wednesday, January 30, 2008

Синтаксис Erlang в двух словах.

Чтобы писать веб-приложения на эрланге, надо его хотя бы немного знать, поэтому попробую в пару постов уложить основные понятия.

Тут лучше конечно почитать какой-нибудь более серьезный туториал, начиная с собственно "Getting Started with Erlang" (русский перевод на рсдн), или "Thinking In Erlang". Однако ж, поскольку 30-50 страниц осилить не у каждого поднимется мозг, я здесь изобразил небольшую шпаргалку (не претендующую на полноценное введение).

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

Для начала самые примитивные вещи:

  • Прежде всего, Эрланг — это язык с динамической типизацией, никакой статической проверки типов тут нет.

  • Литералы-числа в Erlang: 1, 4, 15, 25, 16#1F (в шестнадцатеричной системе), 2#01110110 (в двоичной).
    > 1.
    1
    > 1+2.
    3
    > 1+1.5.
    2.50000
  • Литералы-символы: на самом деле это не отдельный тип, а просто целое число — код символа : $a, $b, $\n $_
    > $a.
    97
    > $\n.
    10
  • Списки задаются в квадратных скобках:
    > [].
    []
    > X = [1,2].
    [1,2].
    > [3 | X].
    [3, 1, 2]
  • Строки — "aba a", "ga a ga".
    > [$a, $b, $c].
     "abc"
    Строки — это на самом деле просто списки символов. Поэтому памяти они занимают немало — в общей сложности 8 байт на один символ строки (на 32-битной машине).
  • Битовые строки (binaries) — эффективное представление бинарных данных
    > <<1, 3, "ba">>.
     <<1,3,98,97>>
    
    Их можно сопоставлять с шаблонами, и быстро передавать туда-сюда. Очень полезная фича Эрланга (правда мы ее использовать сильно не будем).
  • Атомы
    abds
    more
    hello
    ok
    undefined
    
    Начинаются с маленькой буквы, и представляют собой что-то среднее между enum'ами и константными строками, пишутся без кавычек и удобны для разных меток и идентификаторов. Атомы очень похожи на строки, но их нельзя склеивать, вычислять длину и пр., длина их ограничена 256 байтами. Они существенно эффективнее строк в обращении.
  • Еще любые значения еще можно объединять в пары, тройки, четверки, пятерки и так далее, с помощью фигурных скобок: 
    {14, 15} 
    {0, "ba", 3} 
    {$a, [1,2], {3,4}} 
    

Имена переменных всегда начинаются с большой буквы (несмотря на то что они везде называются "переменными", менять их нельзя).

Имена функций и модулей обязательно начинаются с маленькой буквы. Сигнатура функции состоит из ее имени и количества параметров — то есть format/2 и format/3 это разные функции.

Паттерн матчинг (сопоставление с шаблоном) в Erlang выглядит так:

case A of
    Pattern1 -> ...;
    Pattern2 -> ...;
    Pattern3 -> ...;
end

В паттернах можно использовать значок _ который матчит все что угодно (wildcard). В жизни используется как-то так:

case Foo of
    {"HELLO", Name} -> send_response("Hello, " ++ Name);
    "BYE" -> send_response("Bye");
    _ -> send_response("Unknown command")
end

Еще паттерны можно использовать прямо в списке параметров функции:

foo({_, B}) ->
    ...;

foo(X) ->
    ...

что эквивалентно

foo(Y) ->
    case Y of
        {_, B} -> ...
        X -> ...
end.


Плюс, значения можно матчить с помощью знака "равно":

X = {1, 3},
{A, B} = X.

теперь A = 1, а B = 3

Причем, если переменная слева уже определена, в паттерне используется ее значение:

   > B = 4.

Получаем run-time ошибку badmatch, потому что B у нас уже равно трем.

С операторами все почти как обычно:

  • арифметические, +-/*%
  • сравнения =/ , ==, =>, =<
  • склеивание списков ++
  • декомпозиция списков (оператор cons) |
  • битовые band, bor, bxor, bnot

Вот, собственно, практически все. Раздражают в Эрланге поначалу только немного странные правила расстановки точек, запятых и точек с запятой. В двух словах — точка ставится в конце определения функции, запятая — между выражениями в определении функции, а точка с запятой разделяет выражения в case .. of и if.

 


В качестве примера — функция, получающая md5 хэш строки. В стандартной библиотеке уже есть функция md5(), которая получает хэш в виде битовой строки.

> H = erlang:md5("boooo").
<<174,62,131,226,250,179,167,216,104,61,142,239,171,209,231,77>>

Нам же понадобится хэш в виде обычной строки, в шестнадцатиричном представлении, поскольку он используется в процедуре аутентификации на last.fm

Для начала можно преобразовать битовую строку в список байт с помощью стандартной функции:

> binary_to_list(H).
[174,62,131,226,250,179,167,216,104,61,142,239,171,209,231,77]

Теперь функция, которая преобразует 4 бита в один hex символ:

hex(V) ->
    if
    V < 10 ->
            $0 + V;
    true ->
        $a + (V - 10)
     end.

Да, if в erlang — лишь упрощенный вариант case .. of, где вместо паттернов — булевые выражения. Так что кейс "true ->" тут играет роль else

Теперь один байт можно преобразовать в hex так:

> E = 31.
> [hex(E bsr 4), hex(E band 16#F)].
"1f"

Ну и с помощью функции lists:foldl применить это ко всей исходной строке:

binary_to_hex(Bin) ->
    lists:foldl(fun (E, Acc) ->
            [hex(E bsr 4) | [hex(E band 16#F) | Acc]] end,
        [],
        lists:reverse(binary_to_list(Bin))).
% returns hex representation of md5 in reverse byte order
md5_hex(Bin) ->
    binary_to_hex(erlang:md5(Bin)).

Тут

  • fun (E, Acc) -> ... end
         это определение лямбда-функции
  • lists:foldl() это известный функциональным программистам foldl.
  • lists:reverse() разворачивает список задом наперед
  • Конструкция вида [A | B] приклеивает в начало списка B элемент A (см. cons).

Итого получаем

>md5_hex("booo").
"1c052f260d1b34423c32e7c7b29026b9"

Весь исходник (utils.erl)

Про ключевую фичу Erlang — поддержку распределенных приложений поговорим в следующей серии.


Crash Course: веб приложения на Erlang [Дисклеймер]

erlang Почему-то зима выдалась крайне скудной на интересные новости.
Однако это не так уж плохо, можно нормально, не отвлекаясь на чтение RSS заняться непосредственно работой, да и появляется время поковырять разнообразные перспективные технологии, в частности — Erlang, неспроста я ему так уделял внимание последнее время.

В общем, по мотивам своих экзерсисов в erlang, я решил написать небольшой туториал, такой crash course про erlang, причем как средство программирования именно веб-приложений. В качестве примера и сверхзадачи я выбрал веб-клиент (прокси) для социального интернет радио last.fm.

Плюс к этому, меня тут даже рекламировали как пишущего про эрланг — будем оправдывать ;)

"Прокси для ласт.фм", мягко говоря, не очень насущная проблема, но, во-первых, кое-где его действительно блокируют, да и удобно — можно слушать радио в любимом плеере, не используя официальный клиент (раньше такая возможность была, сейчас, кажется, ее убрали).

В конце концов можно слушать ласт.фм без установки клиента, например, на КПК/мобильнике с вайфаем.