Пишем первые модули на Erlang::Журнал СА 9.2009
www.samag.ru
     
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
Журнал "Системный администратор"
Журнал «БИТ»
Подписка
Архив номеров
Где купить
Наука и технологии
Авторам
Рекламодателям
Контакты
   

  Опросы
  Статьи

Дата-центры  

Дата-центры: есть ли опасность утечки данных?

Российские компании уже несколько лет испытывают дефицит вычислительных мощностей. Рост числа проектов,

 Читать далее...

Событие  

В банке рассола ждет сисадмина с полей фрактал-кукумбер

Читайте впечатления о слете ДСА 2024, рассказанные волонтером и участником слета

 Читать далее...

Организация бесперебойной работы  

Бесперебойная работа ИТ-инфраструктуры в режиме 24/7 Как обеспечить ее в нынешних условиях?

Год назад ИТ-компания «Крок» провела исследование «Ключевые тренды сервисного рынка 2023». Результаты

 Читать далее...

Книжная полка  

Читайте и познавайте мир технологий!

Издательство «БХВ» продолжает радовать выпуском интересных и полезных, к тому же прекрасно

 Читать далее...

СУБД PostgreSQL  

СУБД Postgres Pro

Сертификация по новым требованиям ФСТЭК и роль администратора без доступа к данным

 Читать далее...

Критическая инфраструктура  

КИИ для оператора связи. Готовы ли компании к повышению уровня кибербезопасности?

Похоже, что провайдеры и операторы связи начали забывать о требованиях законодательства

 Читать далее...

Архитектура ПО  

Архитектурные метрики. Качество архитектуры и способность системы к эволюционированию

Обычно соответствие программного продукта требованиям мы проверяем через скоуп вполне себе понятных

 Читать далее...

Как хорошо вы это знаете  

Что вам известно о разработках компании ARinteg?

Компания ARinteg (ООО «АРинтег») – системный интегратор на российском рынке ИБ –

 Читать далее...

Графические редакторы  

Рисование абстрактных гор в стиле Paper Cut

Векторный графический редактор Inkscape – яркий представитель той прослойки open source, с

 Читать далее...

День сисадмина  

Учите матчасть! Или как стать системным администратором

Лето – время не только отпусков, но и хорошая возможность определиться с профессией

 Читать далее...

День сисадмина  

Живой айтишник – это всегда движение. Остановка смерти подобна

Наши авторы рассказывают о своем опыте и дают советы начинающим системным администраторам.

 Читать далее...

Виртуализация  

Рынок решений для виртуализации

По данным «Обзора российского рынка инфраструктурного ПО и перспектив его развития», сделанного

 Читать далее...

Книжная полка  

Как стать креативным и востребованным

Издательский дом «Питер» предлагает новинки компьютерной литературы, а также книги по бизнесу

 Читать далее...

Книжная полка  

От создания сайтов до разработки и реализации API

В издательстве «БХВ» недавно вышли книги, которые будут интересны системным администраторам, создателям

 Читать далее...

1001 и 1 книга  
19.03.2018г.
Просмотров: 6227
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

 Читать далее...

12.03.2018г.
Просмотров: 6933
Комментарии: 0
Особенности киберпреступлений в России: инструменты нападения и защита информации

 Читать далее...

12.03.2018г.
Просмотров: 4217
Комментарии: 0
Глубокое обучение с точки зрения практика

 Читать далее...

12.03.2018г.
Просмотров: 3009
Комментарии: 0
Изучаем pandas

 Читать далее...

12.03.2018г.
Просмотров: 3807
Комментарии: 0
Программирование на языке Rust (Цветное издание)

 Читать далее...

19.12.2017г.
Просмотров: 3824
Комментарии: 0
Глубокое обучение

 Читать далее...

19.12.2017г.
Просмотров: 6317
Комментарии: 0
Анализ социальных медиа на Python

 Читать далее...

19.12.2017г.
Просмотров: 3172
Комментарии: 0
Основы блокчейна

 Читать далее...

19.12.2017г.
Просмотров: 3462
Комментарии: 0
Java 9. Полный обзор нововведений

 Читать далее...

16.02.2017г.
Просмотров: 7279
Комментарии: 0
Опоздавших не бывает, или книга о стеке

 Читать далее...

17.05.2016г.
Просмотров: 10647
Комментарии: 0
Теория вычислений для программистов

 Читать далее...

30.03.2015г.
Просмотров: 12367
Комментарии: 0
От математики к обобщенному программированию

 Читать далее...

18.02.2014г.
Просмотров: 14000
Комментарии: 0
Рецензия на книгу «Читаем Тьюринга»

 Читать далее...

13.02.2014г.
Просмотров: 9126
Комментарии: 0
Читайте, размышляйте, действуйте

 Читать далее...

12.02.2014г.
Просмотров: 7079
Комментарии: 0
Рисуем наши мысли

 Читать далее...

10.02.2014г.
Просмотров: 5389
Комментарии: 3
Страна в цифрах

 Читать далее...

18.12.2013г.
Просмотров: 4617
Комментарии: 0
Большие данные меняют нашу жизнь

 Читать далее...

18.12.2013г.
Просмотров: 3428
Комментарии: 0
Компьютерные технологии – корень зла для точки роста

 Читать далее...

04.12.2013г.
Просмотров: 3156
Комментарии: 0
Паутина в облаках

 Читать далее...

03.12.2013г.
Просмотров: 3402
Комментарии: 0
Рецензия на книгу «MongoDB в действии»

 Читать далее...

02.12.2013г.
Просмотров: 3027
Комментарии: 0
Не думай о минутах свысока

 Читать далее...

Друзья сайта  

 Пишем первые модули на Erlang

Архив номеров / 2009 / Выпуск №9 (82) / Пишем первые модули на Erlang

Рубрика: Программирование /  Программирование

ДМИТРИЙ ВАСИЛЬЕВ, больше 10 лет профессионально занимается разработкой ПО, принимает активное участие в различных проектах с открытым исходным кодом

Пишем первые модули на Erlang[1]

Продолжаем изучать Erlang – начнем писать программы, которые выполняются последовательно.

Модули и функции

В Erlang программы состоят из функций, которые вызывают друг друга. Функции в свою очередь группируются и определяются внутри модулей. Модули в Erlang хранятся в файлах с расширением .erl, при этом имя модуля должно быть таким же, как и имя файла. Перед тем как запустить модуль, его нужно скомпилировать. Компилированные модули содержатся в файлах с расширением .beam.

Определение функции состоит из заголовка и тела функции. Заголовок функции состоит из имени функции, которое является атомом, за которым в скобках следуют формальные параметры функции. Количество параметров функции называется арностью (arity). Функции в Erlang уникально определяются именем модуля, именем функции и арностью, то есть две функции, находящиеся в одном модуле с одинаковыми именами, но с разной арностью, являются разными функциями. Стрелка (->) отделяет заголовок функции от ее тела.

Как уже было сказано, мы не можем определять функции в интерактивной сессии оболочки Erlang.

Давайте напишем наш первый модуль и рассмотрим его подробнее. Создадим файл с именем geometry.erl:

-module(geometry).

-export([area/1]).

% Функция для вычисления площади

area({square, Side}) ->

    Side * Side;

area({rectangle, Width, Height}) ->

    Width * Height;

area({circle, Radius}) ->

    3.1415926 * Radius * Radius.

В начале модуля находятся директивы модуля в следующем формате: -директива(значение). Директива module описывает имя модуля, которое должно совпадать с именем файла. Директива export описывает экспортируемые функции (которые будут доступны снаружи модуля) в виде списка в формате имя/арность. В данном случае наш модуль называется geometry и экспортирует одну функцию area с одним аргументом. Заметьте, что каждая директива заканчивается точкой.

Строки, начинающиеся со знака %, являются комментариями, как мы уже рассматривали выше.

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

Попробуем выполнить функцию из нашего модуля:

1> c(geometry).

{ok,geometry}

2> geometry:area({circle, 20}).

1256.63704

3> geometry:area({square, 20}).

400

4> geometry:area({rectangle, 10, 20}).

200

5> geometry:area({triangle, 10, 20, 30}).

** exception error: no function clause matching geometry:area({triangle,10,20,30})

В первой строке мы использовали функцию c(), определенную в оболочке для компиляции нашего модуля. Эта функция возвращает {ok, geometry}, что говорит об успешной компиляции модуля. Вне оболочки модуль может быть скомпилирован с помощью утилиты erlc.

После этого мы делаем несколько вызовов нашей функции, используя нотацию модуль:функция. Мы передаем различные кортежи в качестве аргументов, и выполняется тело того предложения функции, с шаблоном которого совпадает переданный аргумент. В пятой строке мы передали кортеж, который не совпадает ни с одним из шаблонов в определении функции, и получили ошибку.

Более сложный пример

Теперь рассмотрим более сложный пример с использованием ввода/вывода и рекурсии:

-module(persons).

-export([person_list/1]).


person_list(Persons) ->

    person_list(Persons, 0).
 
person_list([{person, FirstName, LastName} | Persons], N) ->

    io:format("~s ~s~n", [FirstName, LastName]),

    person_list(Persons, N + 1);

person_list([], N) ->

    io:format("Total: ~p~n", [N]).

Новый модуль называется persons и экспортирует функцию person_list/1 (с одним аргументом). Заметьте, что в модуле также есть функция person_list/2 (с двумя аргументами), но в данном случае она будет локальной для модуля. Функция person_list/1 вызывает вспомогательную функцию person_list/2.

Функции person_list/2 необходимо передать два аргумента: список пользователей и начальное значение для аргумента-счетчика. Функция person_list/2 состоит из двух предложений. В первом предложении функции мы отделяем первый элемент списка пользователей (заметьте, что мы отделяем имя и фамилию прямо в шаблоне аргумента). Затем используется функция format из библиотечного модуля io, чтобы вывести имя и фамилию пользователя, и после этого мы вызываем person_list/2 с оставшимися пользователями и увеличенным счетчиком пользователей.

Библиотечной функции io:format/2 нужно передать два аргумента – формат вывода и список аргументов. В данном случае формат вывода состоит из двух шаблонов для вывода строк ~s и перевода строки ~n. Модуль io содержит большое количество функций для работы со стандартным вводом/выводом.

Второе (и последнее) предложение функции print_list/2 вызывается, когда список пользователей оказывается пустым (обычно это происходит при окончании вывода пользователей), и выводит общее количество выведенных имен пользователей с помощью аргумента-счетчика. Во втором предложении мы также используем новый шаблон для io:format/2 – ~p, выводящий аргумент в формате, в котором это делает оболочка.

Давайте попробуем использовать наш модуль в интерактивной сессии:

1> c(persons).

{ok,persons}

2> persons:person_list([]).

Total: 0

ok

3> persons:person_list([{person, "Joe", "Armstrong"}]).

Joe Armstrong

Total: 1

ok

4> persons:person_list([{person, "Joe", "Armstrong"},

4> {person, "Mike", "Williams"},

4> {person, "Robert", "Virding"}]).

Joe Armstrong

Mike Williams

Robert Virding

Total: 3

ok

Мы видим, что функция работает, как мы и ожидали.

Ограничители

Часто сравнения с шаблоном для функций бывает недостаточно, и здесь на помощь приходят ограничители (guards), которые позволяют использовать простые тесты и сравнения переменных в шаблонах. Кроме функций, ограничители можно использовать в некоторых других конструкциях, которые мы рассмотрим далее, например, в конструкции case. Для функций ограничители должны быть расположены перед символами ->, разделяющими заголовок и тело функции. Например, можно написать функцию для нахождения максимального значения следующим образом:

max(X, Y) when X > Y ->

    X;

max(_X, Y) ->

    Y.

В первом предложении функции используются ограничители, начиная со слова when. Первое предложение выполняется только в случае, если X > Y, иначе выполняется второе предложение. Во втором предложении первая переменная называется _X – использование подчеркивания в начале имени переменной позволяет избежать предупреждения о неиспользуемой переменной, хотя этим нужно пользоваться с осторожностью, чтобы не пропустить ошибочные ситуации.

Ограничители представляют собой либо одно условное выражение, которое возвращает true/false, либо могут быть записаны как составное выражение следующим образом:

  • Последовательность ограничителей, разделенных точкой с запятой (;), истинна, если хотя бы один из ограничителей в последовательности возвращает true;
  • Последовательность ограничителей, разделенных запятой (,), истинна, только если все ограничители в последовательности возвращают true.

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

  • Атом true (истина).
  • Различные константы и переменные. В ограничителях все они представляют собой ложные значения.
  • Функции для тестирования типов данных и некоторые встроенные функции, например: is_atom, is_boolean, is_tuple, size и др.
  • Сравнение терминов, например =:=, =/=, <, > и т.п.
  • Арифметические операции.
  • Булевские операции.
  • Булевские операции с короткой схемой вычисления (short-circuit).

Условное выполнение

В Erlang есть три формы условного выполнения, которые в большинстве случаев могут быть взаимозаменяемы. С первой формой мы уже познакомились при изучении функций – это использование сравнения с шаблонами в определении функций. Ниже мы рассмотрим еще две формы условного выполнения – конструкции case и if.

В конструкции case сначала выполняется выражение, и затем результат последовательно сравнивается с шаблонами. С шаблонами также можно использовать и ограничители. Рассмотрим пример:

case is_boolean(Variable) of

    true ->

        1;

    false ->

        0

end

В этом (достаточно надуманном) примере в качестве выражения case ... of выполняется функция is_boolean и шаблонами служат true и false. Два предложения разделены точкой с запятой, и конструкция заканчивается ключевым словом end. В случае если подходящий шаблон не будет найден, то будет выкинуто исключение.

Конструкция if использует только ограничители, которые последовательно выполняются, пока не будет получено значение «истина»:

if

    X > Y ->

        true;

    true ->

        false

end

В данном случае ограничитель true действует как конструкция «иначе» в других языках, то есть значением if будет false, если «X =< Y». В случае если ни один из ограничителей не даст значение «истина», будет выкинуто исключение.

Анонимные функции

Определяются с ключевым словом fun и похожи на определение обычных функций за исключением отсутствия имени. Рассмотрим пример:

-module(times).

-export([times/1]).

times(N) ->

    fun

        (X) when is_number(X) ->

            X * N;

        (_) ->

            erlang:error(number_expected)

    end.

Здесь функция times является функцией высшего порядка, так как возвращает другую функцию. Определение анонимной функции между ключевыми словами fun ... end состоит из двух предложений. В первом предложении с помощью ограничителя is_number мы определяем, что передано число (число может быть целым или вещественным), и умножаем его на аргумент, переданный в основную функцию. Во втором предложении мы немного забегаем вперед и используем генерацию исключений, которая будет рассмотрена в следующем разделе.

Попробуем выполнить функцию:

1> c(times).

{ok,times}

2> N2 = times:times(2).

#Fun<times.0.120017377>

3> N2(4).

8

4> N10 = times:times(10).

#Fun<times.0.120017377>

5> N10(4).

40

В строке 2 мы используем функцию times:times для получения функции, умножающей значение на 2, и в строке 4 создается функция, умножающая значение на 10.

Стандартный модуль lists экспортирует некоторое количество функций, которые принимают функции в качестве аргументов, например, функция lists:map вызывает функцию, используя каждый элемент списка по очереди:

6> Double = times:times(2).

#Fun<times.0.120017377>

7> lists:map(Double, [1, 2, 3, 4]).

[2,4,6,8]

Обработка исключений

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

Исключения в своем коде можно создать, используя одну из встроенных функций:

exit(Why) – используется, когда нужно действительно прервать выполнение текущего процесса. Если это исключение не перехватывается, то всем процессам, присоединенным к данному, посылается сообщение {'EXIT', Pid, Why}.

throw(Why) – используется для генерации исключения, которое вызывающая сторона, возможно, захочет перехватить. Таким образом, мы документируем, что наша функция может генерировать данное исключение;

erlang:error(Why) – используется для аварийных ситуаций, которые не ожидает вызывающая сторона.

Теперь разберемся, как эти исключения обрабатывать. В Erlang существует два способа обработки исключений – выражение catch и конструкция try ... catch.

Выражение catch возвращает либо значение под-выражения, либо информацию об ошибке в зависимости от типа ошибки. Рассмотрим на примере:

1> catch 2 + 2.
4

2> catch 2 + a.
 
{'EXIT',{badarith,[{erlang,'+',[2,a]},

                   {erl_eval,do_apply,5},

                   {erl_eval,expr,5},

                   {shell,exprs,6},

                   {shell,eval_exprs,6},

                   {shell,eval_loop,3}]}}


3> catch exit("Exit").
 
{'EXIT',"Exit"}

4> catch throw("Throw").

"Throw"

5> catch erlang:error("Error").

{'EXIT',{"Error",

         [{erl_eval,do_apply,5},

          {erl_eval,expr,5},

          {shell,exprs,6},

          {shell,eval_exprs,6},

          {shell,eval_loop,3}]}}

В первой строке мы пробуем catch с выражением «2 + 2», которое успешно выполняется, возвращая 4. Во второй строке делается попытка сложить целое и атом, и catch возвращает описание ошибки в виде {'EXIT', {ошибка, стек вызовов}}. Следующие три строки показывают возвращаемые значения в зависимости от способа генерации исключений. Часто catch используют совместно с конструкцией case для обработки ошибок в выражениях.

Конструкция try ... catch позволяет обрабатывать только необходимые для обработки типы ошибок и даже может быть совмещена с конструкцией, похожей на case. Пример:

try 2 + a of

    Value ->

        ok

catch

    error:_ ->

        error

end.

Мы пытаемся выполнить выражение «2 + a», и шаблоны между of ... catch соответствуют шаблонам в выражении case. Шаблоны между catch ... end (в которых также можно использовать ограничители) используются для сопоставления с ошибками, где ошибка описывается как тип:значение.

Библиотечные модули

В состав Erlang включено большое количество стандартных библиотечных модулей. Их подробное описание можно найти по ссылке: http://erlang.org/doc/man_index.html.

Ниже описываются наиболее полезные модули:

erlang – содержит все встроенные функции Erlang. Большинство функций из этого модуля доступны без указания имени модуля, но к остальным нужно обращаться только по полному имени, с указанием модуля;

file – интерфейс к файловой системе, содержащий функции для работы с файлами;

io – интерфейс к стандартному серверу ввода/вывода. Содержит функции для чтения/записи файлов, в том числе стандартных устройств ввода/вывода;

lists – содержит функции для работы со списками;

math – модуль, содержащий стандартные математические функции;

string – содержит функции для работы со строками.

***

Мы рассмотрели основы последовательного программирования в Erlang. Более подробную информацию о функциях, модулях, ограничителях, условных выражениях, анонимных функциях и исключениях можно найти в справочном руководстве по Erlang: http://erlang.org/doc/reference_manual/part_frame.html.



[1] В первой части статьи «Знакомьтесь, Erlang» (№8, 2009 г.) были рассмотрены особенности языка, основные типы данных, переменные и сравнение с шаблонами.


Комментарии отсутствуют

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-45
E-mail: sa@samag.ru