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

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

Интеграция Open Source-решений  

Open Source в облачной среде

Облачные решения становятся всё более популярными в мире. Компании стремятся использовать их для

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

Автоматизация  

Нейросеть вам в руки! Как использовать ИИ для автоматизации задач

Использование ИИ для автоматизации задач помогает компании получить конкурентное преимущество, поскольку объединение

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

Рынок труда  

Специалист по этическому ИИ, инженер по квантовым вычислениям или аналитик по метавселенной?

Новые тенденции в развитии ИТ могут привести к возникновению новых специальностей в

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

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

Учитесь убеждать и побеждать

Издательство «БХВ», как всегда, порадовало своих читателей хорошими книжными новинками. Кроме популярных

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

Сетевая инфраструктура  

Как удаленная работа меняет подход к сетевой инфраструктуре?

С увеличением числа сотрудников, работающих из дома, организации сталкиваются с необходимостью создания

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

Мониторинг  

Какой мониторинг нужен сегодня?

По мнению экспертов ГК InfoWatch, действия сотрудников – самая распространенная причина инцидентов

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

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

Руководство для тех, кто увлечен ИИ, программированием. И дизайном

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

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

Мобильные приложения  

Искусственный интеллект в мобильных приложениях: возможности и перспективы

Обзор современных применений ИИ в мобильных приложениях, анализ перспектив развития этой технологии,

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

ИТ-образование  

Как сделать ИТ-образование эффективным?

Эксперты ИТ-отрасли отвечают на вопросы «СА». Обсуждаем ключевые аспекты для улучшения образовательных

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

Work-life balance  

Как айтишнику найти баланс между работой и личной жизнью?

Обсуждаем инструменты для эффективного управления временем, снижения уровня стресса и достижения гармонии. На

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

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

Всё самое нужное – под одной обложкой

Отличительная черта книжных новинок, выпущенных недавно издательством «БХВ» – это их универсальность. Не просто

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

ИТ-инфраструктура  

Системы мониторинга ИТ-инфраструктуры-2025

Без мониторинга ИТ-инфраструктуры не обходится ни одна компания, хотя бы потому, что

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

Открытое ПО  

Безопасность Open Source: рискуем или контролируем?

Компания «Кросс технолоджис» изучила, как используется ПО с открытым кодом в компаниях

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

Работа с нейросетью  

Скажи, есть ли у тебя AI, и я скажу, кто ты

Недавно сервис по поиску работы SuperJob выяснил, что каждый второй россиянин уже

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Друзья сайта  

 Пишем первые модули на 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