Учебник по Haskell | страница 63



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

where res = True

even (Succ Zero) = res

where res = False

even x = even res

where (Succ (Succ res)) = x

Конечно в этом примере where не нужны, но здесь они приведены для иллюстрации привязки where-

выражения к данному уравнению. Мы определили три локальных переменных с одним и тем же именем.

where-выражения могут быть и у значений, которые определяются внутри where-выражений. Но лучше

избегать сильно вложенных выражений.

60 | Глава 4: Декларативный и композиционный стиль

let-выражения

В композиционном стиле функция вычисления площади треугольника будет выглядеть так:

square a b c = let p = (a + b + c) / 2

in

sqrt (p * (p