×
Traktatov.net » Изучай Haskell во имя добра! » Читать онлайн
Страница 29 из 245 Настройки

Мы помещаем ключевое слово >where после охранных выражений (обычно его печатают с тем же отступом, что и сами охранные выражения), а затем определяем несколько имён или функций. Эти имена видимы внутри объявления функции и позволяют нам не повторять код. Если вдруг нам вздумается вычислять ИМТ другим методом, мы должны исправить способ его вычисления только один раз.

Использование ключевого слова >where улучшает читаемость, так как даёт имена понятиям и может сделать программы быстрее за счёт того, что переменные вроде >bmi вычисляются лишь однажды. Попробуем зайти ещё дальше и представить нашу функцию так:

>bmiTell :: Double -> Double -> String

>bmiTell weight height

>  | bmi <= skinny = "Слышь, эмо, ты дистрофик!"

>  | bmi <= normal = "По части веса ты в норме.

>                     Зато, небось, уродец!"

>  | bmi <= fat = "Ты толстый!

>                  Сбрось хоть немного веса!"

>  | otherwise = "Мои поздравления, ты жирный боров!"

>  where bmi = weight / height ^ 2

>        skinny = 18.5

>        normal = 25.0

>        fat = 30.0

ПРИМЕЧАНИЕ. Заметьте, что все идентификаторы расположены в одном столбце. Если не отформатировать исходный код подобным образом, язык Haskell не поймёт, что все они – часть одного блока определений.

Область видимости декларации where

Переменные, которые мы определили в секции >where нашей функции, видимы только ей самой, так что можно не беспокоиться о том, что мы засоряем пространство имён других функций. Если же нам нужны переменные, доступные в нескольких различных функциях, их следует определить глобально. Привязки в секции >where не являются общими для различных образцов данной функции. Предположим, что мы хотим написать функцию, которая принимает на вход имя человека и, если это имя ей знакомо, вежливо его приветствует, а если нет – тоже приветствует, но несколько грубее. Первая попытка может выглядеть примерно так:

>greet :: String -> String

>greet "Хуан" = niceGreeting ++ " Хуан!"

>greet "Фернандо" = niceGreeting ++ " Фернандо!"

>greet name = badGreeting ++ " " ++ name

>  where niceGreeting = "Привет! Так приятно тебя увидеть,"

>        badGreeting = "О, чёрт, это ты,"

Однако эта функция работать не будет, так как имена, введённые в блоке >where, видимы только в последнем варианте определения функции. Исправить положение может только глобальное определение функций >niceGreeting и >badGreeting, например:

>badGreeting :: String

>badGreeting = "О, чёрт, это ты,"


>niceGreeting :: String

>niceGreeting = "Привет! Так приятно тебя увидеть,"


>greet :: String -> String

>greet "Хуан" = niceGreeting ++ " Хуан!"

>greet "Фернандо" = niceGreeting ++ " Фернандо!"

>greet name = badGreeting ++ " " ++ name

Сопоставление с образцами в секции where

Можно использовать привязки в секции >where и для сопоставления с образцом. Перепишем секцию >where в нашей функции так:

>  ...

>  where bmi = weight / height 2

>        (skinny, normal, fat) = (18.5, 25.0, 30.0)

Давайте создадим ещё одну простую функцию, которая принимает два аргумента: имя и фамилию, и возвращает инициалы.

>initials :: String –> String –> String