Пишем первые модули на 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г.
Просмотров: 6140
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

02.12.2013г.
Просмотров: 2999
Комментарии: 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