Изучай Haskell во имя добра! (Липовача) - страница 35

>  | 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, видимы только в последнем варианте определения функции. Исправить положение может только глобальное определение функций