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

>  | weight / height ^ 2 <= 30.0 = "Ты толстый!

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

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

Ну-ка проверим, не толстый ли я…

>ghci> bmiTell 85 1.90

>"По части веса ты в норме. Зато, небось, уродец!"

Ура! По крайней мере, я не толстый! Правда, Haskell обозвал меня уродцем. Ну, это не в счёт.

ПРИМЕЧАНИЕ. Обратите внимание, что после имени функции и её параметров нет знака равенства до первого охранного выражения. Многие новички ставят этот знак, что приводит к ошибке.

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

>max' :: (Ord a) => a –> a –> a

>max' a b

>  | a <= b = b

>  | otherwise = a

Продолжим: напишем нашу собственную функцию сравнения, используя охранные выражения.

>myCompare :: (Ord a) => a –> a –> Ordering

>a `myCompare` b

>  | a == b = EQ

>  | a <= b = LT

>  | otherwise = GT


>ghci> 3 `myCompare` 2

>GT

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

Где же ты, where?!

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

В прошлом разделе мы определили вычислитель ИМТ и «ругалочку» на его основе таким образом:

>bmiTell :: Double -> Double -> String

>bmiTell weight height

>  | weight / height ^ 2 <= 18.5 = "Слышь, эмо, ты дистрофик!"

>  | weight / height ^ 2 <= 25.0 = "По части веса ты в норме.

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

>  | weight / height ^ 2 <= 30.0 = "Ты толстый!

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

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

Заметили – мы повторили вычисление три раза? Операции копирования и вставки, да ещё повторенные трижды, – сущее наказание для программиста. Раз уж у нас вычисление повторяется три раза, было бы очень удобно, если бы мы могли вычислить его единожды, присвоить результату имя и использовать его, вместо того чтобы повторять вычисление. Можно переписать нашу функцию так:

>bmiTell :: Double -> Double -> String bmiTell weight height

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