52700.fb2
square a b c = sqrt (p * (p - a) * (p - b) * (p - c)) where
p = (a + b + c) / 2
За определением функции следует специальное слово where, которое вводит локальные имена-
синонимы. При этом аргументы функции включены в область видимости имён. Синонимов может быть
несколько:
square a b c = sqrt (p * pa * pb * pc)
where p
= (a + b + c) / 2
pa = p - a
pb = p - b
pc = p - c
Отметим, что отступы обязательны. Haskell по отступам понимает, что эти выражения относятся к where.
Как и в случае объявления функций порядок следования локальных переменных в where-выражении не
важен. Главное чтобы в выражениях справа от знака равно мы пользовались именами из списка аргументов
исходной функции или другими определёнными именами. Локальные переменные видны только в пределах
той функции, в которой они вводятся.
Что интересно, слева от знака равно в where-выражениях можно проводить декомпозицию значений, так-
же как и в аргументах функции:
pred :: Nat -> Nat
pred x = y
where (Succ y) = x
Эта функция делает тоже самое что и функция
pred :: Nat -> Nat
pred (Succ y) = y
В where-выражениях можно определять новые функции а также выписывать их типы:
add2 x = succ (succ x)
where succ :: Int -> Int
succ x = x + 1
А можно и не выписывать, компилятор догадается:
add2 x = succ (succ x)
where succ x = x + 1
Но иногда это бывает полезно, при использовании классов типов, для избежания неопределённости при-
менения.
Приведём ещё один пример. Посмотрим на функцию фильтрации списков, она определена в Prelude:
filter :: (a -> Bool) -> [a] -> [a]
filter
p
[]
= []
filter
p
(x:xs) = if p x then x : rest else rest
where rest = filter p xs
Мы определили локальную переменную rest, которая указывает на рекурсивный вызов функции на остав-
шейся части списка.
where-выражения определяются для каждого уравнения в определении функции:
even :: Nat -> Bool
even Zero
= res