Главная » Haskell » Бинарные операции

0

В языке Haskell для удобства программирования  имеется возможность определять бинарные операции, назначая им имена в виде значков или их последовательностей. Собственно, все арифметические операции: (*), (/) и т. д. определены в стандартном модуле Prelude (хотя это и сделано через примитивные  функции для базовых типов). Эта техника позволяет создавать функции, которые записываются между своими аргументами и имеют более традиционный внешний вид (с точки зрения математики).

В качестве имён бинарных операций можно пользоваться любыми последовательностями  неалфавитных  символов. Нельзя лишь называть операции так, как уже названы некоторые операции из стандартного модуля Prelude  (хотя в случае необходимости можно отменить импорт соответствующих операций из этого модуля, что позволит их переопределить), ну и невозможно дать бинарным операциям имена, которые представляют собой зарезервированные для нужд языка последовательности символов (например, (::), (=>) или (->),  которые используются в сигнатурах функций).

При определении бинарных операций используются круглые скобки (), в которых записывается наименование операции. В случае, если такая операция находится между своими операндами, то скобки  необходимо опускать. Вот так, к примеру, определена операция  конкатенации  списков в стандартном модуле Prelude (операция (++) подробно описывается на стр. 171):

(++)  :: [a] ->  [a]  ->  [a] []          ++  ys  = ys

(x:xs) ++ ys  = x  : (xs  ++ ys)

Как  видно из этого определения, в сигнатуре бинарной операции используются круглые скобки, а в её определении  — нет.

Определение приоритета и ассоциативности

Для бинарных операций возможно определение приоритета исполнения и ассоциативности.  Для этих целей используется следующий набор ключевых слов: infix, infixl и infixr. Эти ключевые слова являются декларациями верхнего уровня, которые видны повсюду в модуле, где определяются бинарные операции.

Синтаксис определения приоритета и ассоциативности прост. На  отдельной строке вначале идёт одно из перечисленных ключевых слов. Следующим  термом после пробела записывается  значение приоритета  — целое число от 0 до 9. Чем выше число, тем выше приоритет операции. После числа через запятую перечисляются бинарные операции (просто наименования,  без круглых скобок), которые имеют заданный приоритет  и ассоциативность. Вот так, к примеру, определены приоритеты и  ассоциативность бинарных операций в стандартном модуле Prelude:

infixr 9   .

infixl 9   !!

infixr 8   ^, ^^, **

infixl 7   *, /, ‘quot‘, ‘rem‘, ‘div‘,  ‘mod‘, :%,  % infixl 6   +,  -

infixr  5    : infixr  5    ++

infix  4   ==,  /=, <,  <=,  >=,  >,  ‘elem‘, ‘notElem‘ infixr 3   &&

infixr  2    || infixl  1    >>,  >>= infixr  1    =<<

infixr 0   $, $!, ‘seq‘

Сами ключевые слова, как должно быть понятно, определяют  ассоциативность. Слово infix регламентирует тот факт, что последовательное применение операций невозможно, ассоциативности нет в принципе. Действительно, для вышеуказанных операций с  приоритетом 4 ((==), (/=)  и т. д.), которые  являются логическими  операциями сравнения, записи вроде «1 == 2 == 3» бессмысленны. Для прочих же  бинарных операций подобные записи вполне  осмысленны, а потому ассоциативность определять необходимо.

Ключевые слова infixl  и  infixr  определяет  левую и  правую  ассоциативность  соответственно. Например,  для  арифметических   операций (+)  и  (-) определена левая ассоциативность, которая  предполагает, что в записях вида

«1 + 2 + 3» и «3 2 1» скобки будут восстанавливаться по ассоциативности влево: «((1 + 2)  + 3)»  и «((3 2)  1)».  Если  для операции сложения (+) это не столь важно, то результат операции вычитания (-) очень зависит от типа ассоциативности.

Как  уже сказано, значение приоритета может быть из интервала от 0 до 9. однако имеется ещё одно значение  — 10, наивысший приоритет. Этот приоритет нельзя назначить ни одной операции, но его имеет операция применения функции к своим аргументам. Поэтому в выражениях с операциями можно использовать функции без заключения их в скобки.

Инфиксная нотация

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

заключить в обратные апострофы: (‘).  Обычно таким образом  записываются функции целочисленного деления и получения остатка, поскольку для них нет устоявшихся математических знаков, а они соответствуют бинарным математическим операциям:

even n = (n  ‘mod‘  2)  == 0

Эта  функция  является предикатом, который  возвращает значение  True

на чётных величинах и False на нечётных (подробно описывается на стр. 119).

Функции с двумя аргументами, которые используются в качестве бинарных операций, могут также получить указание относительно их приоритета и типа ассоциативности. Для этого их имена в обратных  апострофах (‘)  необходимо перечислить в соответствующих декларациях infix, infixl или infixr.

Источник: Душкин Р. В., Справочник по языку Haskell. М.: ДМК Пресс, 2008. 544 с., ил.

По теме:

  • Комментарии