← На главную

Написал свой первый простенький скрипт на Erlang

Что не говори, а изучение новых языков программирования редко оказывается пустой тратой времени. Даже если изучаемый язык не придется использовать на практике, в процессе изучения вы скорее всего в той или иной мере сломаете себе мозг (в хорошем смысле), то есть, откроете для себя новые подходы к решению неких проблем. В дальнейшем эти подходы могут быть использованы вами независимо от языка программирования.

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

Краткая информация о языке:

  • Erlang – функциональный язык программирования (правда, не чистый, как Haskell) со строгой динамической типизацией;
  • Программы на Erlang транслируются в байт-код, который затем выполняется виртуальной машиной;
  • Аргументы передаются функциям только по значению, глобальные переменные и указатели отсутствуют, присвоение значений переменным допускается только при их объявлении, управление памятью происходит автоматически;
  • Прочие фишки функционального программирования – сопоставление с образцом, «лямбды», замыкания, REPL-разработка и тп, правда нет поддержки каррирования и ленивых вычислений;
  • Есть поддержка исключений;
  • Легковесные процессы, отсутствие разделяемой памяти (чуть подробнее об этом будет рассказано ниже);
  • Развитый инструментарий – EUnit и Common Test для написания тестов, EDoc для документирования кода, Dialyzer для проверки типов и TypeEr для автоматического вывода типов (в языке с динамической типизацией!), Rebar для сборки проектов и установки зависимостей, dbg для отладки, а также xref, erl_tidy и другие;
  • Большое количество годных библиотек и фреймворков, а также исчерпывающая документация к ним;
  • Широкая область применения – на Erlang написаны XMPP-сервер ejabberd, СУБД Mnesia, CouchDB, Couchbase, Scalaris и Riak, система обмена сообщениями RabbitMQ, программа 3D-моделирования Wings 3D, видеостриминговый сервер Erlyvideo, веб-серверы Cowboy и Yaws, веб-фреймворк Nitrogen, серверная часть игры Call of Duty, Map-Reduce фреймворк Disco, CMS Zotonic, распределенная система нагрузочного тестирования Tsung, сервер API системы управления конфигурацией Chef и другие;
  • Используется в Yahoo, Amazon, Facebook, Motorola, Ericsson, Яндексе, WhatsApp, Nokia, GitHub, Blizzard, Hypercomments и не только;

Важной отличительной особенностью Erlang является модель легковесных процессов. Эти процессы не являются процессами операционной системы. Только виртуальная машина знает об их существовании и она же распределяет между ними процессорное время.

Процессы не имеют никакой разделяемой памяти – взаимодействие происходит путем обмена сообщениями. Этот подход избавляет нас от множества проблем многопоточного программирования. Основной недостаток заключается в том, что если процесс не будет своевременно забирать сообщения из очереди, могут возникнуть проблемы.

Благодаря описанной модели, Erlang-процессы могут быть с легкостью распределены как по ядрам одного процессора, так и по нескольким компьютерам, объединенным в сеть. Кроме того, в Erlang предусмотрены средства, позволяющие обновлять код приложения без его остановки. Следует также отметить возможность создания процессов-наблюдателей, которые, к примеру, могут перезапускать всю группу зависящих друг от друга процессов в случае возникновения исключения в одном из них.

Как я уже когда-то писал, при изучении нового языка программирования обычно я беру прототип программы на уже знакомом мне языке, а затем переписываю его. При изучении Erlang в качестве такого прототипа я выбрал программу, решающую задачу о дне системного администратора. В результате у меня получилась такая библиотека для работы с датами:

-module(dates). -import(lists). % -compile(export_all). -export([is_leap_year/1, days_in_year/1, days_in_month/2, days_from_epoch/3, day_of_week/3]). -define(DEBUG, false). -define(JANUARY, 1). -define(FEBRUARY, 2). -define(APRIL, 4). -define(JUNE, 6). -define(SEPTEMBER, 9). -define(NOVEMBER, 11). -define(DECEMBER, 12). -ifdef(DEBUG). -define(CHECK_MONTH(Month), case (Month >= ?JANUARY) and (Month =< ?DECEMBER) of false -> erlang:error(badarg); _ -> ok end ). -else. -define(CHECK_MONTH(_), ok). -endif. is_leap_year(Y) -> if Y rem 400 == 0 -> true; Y rem 100 == 0 -> false; Y rem 4 == 0 -> true; true -> false end. days_in_year(Y) -> case is_leap_year(Y) of true -> 366; false -> 365 end. days_in_month(?FEBRUARY, IsLeapYear) -> if IsLeapYear -> 29; true -> 28 end; days_in_month(Month, _) -> ?CHECK_MONTH(Month), case lists:member( Month, [?APRIL,?JUNE,?SEPTEMBER,?NOVEMBER]) of true -> 30; _ -> 31 end. months_before(?JANUARY) -> []; months_before(Month) -> ?CHECK_MONTH(Month), [ Month - 1 | months_before(Month - 1) ]. % число дней с 1-го января 1-го года (не включая) days_from_epoch(Year,Month,Day) -> ?CHECK_MONTH(Month), IsLeap = is_leap_year(Year), YDays = lists:map(fun days_in_year/1, lists:seq(1,Year-1)), MDays = lists:map( fun(M) -> days_in_month(M, IsLeap) end, months_before(Month)), lists:sum(YDays) + lists:sum(MDays) + Day-1. day_of_week(Year,Month,Day) -> days_from_epoch(Year,Month,Day) rem 7.

А вот и скрипт main.erl, определяющий, на какое число июля приходится день системного администратора в 2012-ом году:

#!/usr/bin/env escript -import(lists). -import(dates). -define(JULY, 7). -define(FRIDAY, 4). sys_admin_day_in_year(Y) -> Pred = fun(D) -> dates:day_of_week(Y, ?JULY, D) == ?FRIDAY end, lists:last(lists:filter(Pred, lists:seq(1,31))). main(_Args) -> io:format("~w\n", [ sys_admin_day_in_year(2012) ]).

Установка Erlang и запуск скрипта:

sudo apt-get install erlang chmod u+x ./main.erl ./main.erl

Тут, конечно, никаким хайлоадом или распределенностью даже не пахнет, но, думаю, синтаксис я уже более-менее освоил. Запустив скрипт, мы узнаем, что день сисадмина в этом году приходится на 27-е июля. Не забудьте поздравить знакомых админов!

Узнать больше об Erlang можно из книги Learn You Some Erlang for Great Good. Это аналог книги «Изучай Haskell во имя добра», только про Erlang.

Дополнение: Впечатления от Erlang после года работы с ним