# Глава 8. Мир операторов Оператор (англ. operator) — частный случай функции. В предыдущих главах мы уже познакомились с ними, осталось объяснить подробнее. ## Что такое оператор Вспомним наше самое первое выражение: ```haskell 1 + 2 ``` Функция `+` записана в инфиксной (англ. infix) форме, то есть между своими аргументами. Такая запись выглядит естественнее, нежели обычная префиксная: ```haskell (+) 1 2 ``` Видите круглые скобки? Они говорят о том, что данная функция предназначена для инфиксной записи. Автор этой функции изначально рассчитывал на инфиксную форму использования `1 + 2`, а не на обычную `(+) 1 2`, именно поэтому имя функции в определении заключено в круглые скобки: ```haskell (+) :: ... ``` Функции, предназначенные для инфиксной формы применения, называют **операторами.** Но тут требуется уточнение. Оператор отрицания обозначается знаком минус: `-`. Например, `-False` — это `True`. И отрицание — единственный префиксный оператор в Haskell. Если же имя функции не заключено в круглые скобки, подразумевается, что мы рассчитываем на обычную форму её применения. Однако и в этом случае можно применять её инфиксно, но имя должно заключаться в обратные одинарные кавычки (англ. backtick). {#block-infix} Определим функцию `isEqualTo`, являющуюся аналогом оператора проверки на равенство для двух целочисленных значений: ```haskell {.example_for_playground .example_for_playground_001} isEqualTo :: Int -> Int -> Bool isEqualTo x y = x == y ``` При обычной форме её применение выглядело бы так: ```haskell ... if isEqualTo code1 code2 then ... else ... where code1 = 123 code2 = 124 ... ``` Но давайте перепишем в инфиксной форме: ```haskell ... if code1 `isEqualTo` code2 then ... else ... where code1 = 123 code2 = 124 ... ``` Гораздо лучше, ведь теперь код читается как обычный английский текст: ```haskell ... if code1 `isEqualTo` code2 ... if code1 is equal to code2 ... ... ``` Строго говоря, название «оператор» весьма условно, мы можем его и не использовать. Говорить о функции сложения столь же корректно, как и об операторе сложения. Заведите функцию `isDivisibleBy`, принимающую два целых числа. Функция должна отдавать `True`, если первый аргумент делится без остатка на второй, и `False` в обратном случае. {.task_text} Для получения остатка от деления примените встроенную функцию `mod` в инфиксной форме. {.task_text} В теле функции `main` перепишите **последнее** применение `isDivisibleBy` на инфиксную форму. {.task_text} ```haskell {.task_source #haskell_chapter_0080_task_0010} module Main where -- Your code here main :: IO () main = do print (isDivisibleBy 55 11) print (isDivisibleBy 46 9) print (isDivisibleBy 80 8) ``` Для применения функции в инфиксной форме используйте обратные одинарные кавычки. {.task_hint} ```haskell {.task_answer} module Main where isDivisibleBy :: Int -> Int -> Bool isDivisibleBy a b = a `mod` b == 0 main :: IO () main = do print (isDivisibleBy 55 11) print (isDivisibleBy 46 9) print (80 `isDivisibleBy` 8) ``` ## Зачем это нужно? Почти все ASCII-символы (а также их всевозможные комбинации) можно использовать в качестве операторов в Haskell. Это даёт нам широкие возможности для реализации различных EDSL (англ. Embedded Domain Specific Language), своего рода «языков в языке». Вот пример: ```haskell div ! class_ "nav-wrapper" $ a ! class_ "brand-logo sans" ! href "/" $ "#ohaskell" ``` Любой, кто знаком с веб-разработкой, мгновенно узнает в этом коде HTML. Это [кусочек кода](https://github.com/denisshevchenko/ohaskell.guide/blob/master/src/CreateHtmlTemplates.hs#L56), строящего HTML-шаблон для веб-варианта данной книги. То что вы видите — это совершенно легальный Haskell-код, в процессе работы которого генерируется реальный HTML: тег `<div>` с классом `nav-wrapper`, внутри которого лежит `<a>`-ссылка с двумя классами, корневым адресом и внутренним текстом `#ohaskell`. Идентификаторы `div`, `class_` и `href` — это имена функций, а символы `!` и `$` — это операторы, записанные в инфиксной форме. Самое главное, что для понимания этого кода нам абсолютно необязательно знать, где определены все эти функции/операторы и как они работают. Это важная мысль, которую я неоднократно буду повторять в последующих главах: чтобы использовать функции, нам вовсе **необязательно** знать их внутренности. А про EDSL запомните, мы с ними ещё встретимся. Напишите оператор `@`, который возвращает сумму квадратов двух целочисленных аргументов. {.task_text} Используйте его в теле `main` так, чтобы вывод функции `print` не изменился. {.task_text} ```haskell {.task_source #haskell_chapter_0080_task_0020} module Main where -- Your code here main :: IO () main = do print (5*5 + 4*4) print (8*8 + 1*1) ``` В объявлении и определении оператора обрамите его имя круглыми скобками. {.task_hint} ```haskell {.task_answer} module Main where (@) :: Int -> Int -> Int (@) a b = a*a + b*b main :: IO () main = do print (5 @ 4) print (8 @ 1) ```
Отправка...
Наша группа в telegram. Здесь можно задавать вопросы и общаться.
Задонатить. Если вам нравится курс, вы можете поддержать развитие площадки!