← На главную

Написал свой первый простенький скрипт на 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 после года работы с ним