> | bmi <= 25.0 = "По части веса ты в норме.
> Зато, небось, уродец!"
> | bmi <= 30.0 = "Ты толстый!
> Сбрось хоть немного веса!"
> | otherwise = "Мои поздравления, ты жирный боров!"
> where bmi = weight / height ^ 2
Мы помещаем ключевое слово >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
, видимы только в последнем варианте определения функции. Исправить положение может только глобальное определение функций