Как было показано в третьей лекции, охрана и локальные переменные используются в функциональном программировании исключительно для простоты записи и понимания текстов программ. Haskell не обошёл своим вниманием и этот аспект, в его синтаксисе имеются специальные средства, которые позволяют организовывать охрану и использовать локальные переменные.
Если возникла необходимость определить какую-либо функцию с использованием механизма охраны, то для этой цели необходимо использовать символ вертикальной черты " | " :
sign x | x > 0 = 1
| x == 0 = 0
| x < 0 = -1
Функция sign в предыдущем примере использует три охраняющие конструкции, каждая из которых отделена вертикальной чертой от предыдущего определения. В принципе, таких охраняющих конструкций может быть неограниченное количество. Их разбор идёт, естественно, сверху вниз, и если существует непустое пересечение в определении охраны, то сработает та конструкция, которая находится раньше (выше) в записи определения функции.
Для того чтобы облегчить написание программ, сделать их более читабельными и простыми для понимания в том случае, когда в каком-либо определении функции записано большое количество клозов, в Haskell’е существует ключевое слово "case". При помощи этого слова можно не записывать клозы определения функций так, как это принято в "чистом" функциональном программировании, а несколько сократить запись. Вот общий вид определения функций с ключевым словом "case":
Function X1 X2 ... Xk = case (X1, X2, ..., Xk) of
(P11, P21, ..., Pk1) ® Expression1
...
(P1n, P2n, ..., Pkn) ® Expressionn
В приведенном выше описании жирным шрифтом выделены служебные слова и символы языка.
Так функция, которая возвращает список из первых n элементов заданного списка, может быть определена следующим образом при помощи служебного слова "case":
takeFirst n l = case (n, l) of
(0, _) -> []
(_, []) -> []
(n, (x:xs)) -> (x) : (takeFirst (n – 1) xs)
И такая запись будет полностью эквивалентна обычному определению функции:
takeFirst 0 _ = []
takeFirst _ [] = []
takeFirst n (x:xs) = (x) : (takeFirst (n – 1) xs)
Пришло время объяснить понятие маски подстановки. В Haskell’е маску обозначают символом нижней черты " _ " (абсолютно так же, как и в Prolog’е). Этот символ заменяет любой образец и является своего рода анонимной переменной. Если в выражении клоза нет необходимости использования переменной образца, то её можно заменить маской подстановки. При этом, естественно, происходят отложенные вычисления — то выражение, которое может быть подставлено вместо маски, не вычисляется.
Другим способом использования охраняющих конструкций является использование конструкции "if-then-else". В Haskell’е реализована и эта возможность. Формально, эта конструкция может быть легко трансформирована в выражение с использованием служебного слова "case". Можно даже считать, что выражение:
if Exp1 then Exp2 else Exp3
Является сокращением выражения:
case (Exp1) of
(True) -> Exp2
(False) -> Exp3
Естественно, что тип Exp1 должен быть Bool, а типы выражений Exp2 и Exp3 совпадать (ведь именно значения этих выражений будет возвращено определяемой через конструкцию "if-then-else" функцией).
Для использования локальных переменных (в смысле функциональной парадигмы программирования) в Haskell’е существует два типа записи. Первый тип полностью соответствует математической нотации, введенной в третьей лекции:
let y = a * b
f x = (x + y) / y
in f c + f d
Другим способом определения локальной переменной является её описание после использования. В этом случае используется служебное слово "where", которое ставится в конце выражения:
f x y | y > z = y – z
| y == z = 0
| y < z = z – y
where z = x * x
Видно, что Haskell поддерживает два способа записи определения локальных переменных — префиксный (при помощи служебного слова "let") и постфиксный (при помощи служебного слова "where"). Оба способа являются равнозначными, их употребление зависит только от наклонностей программиста. Однако обычно постфиксный способ записи используется в выражениях, где также есть охрана, в то время как префиксный способ записи используется в остальных случаях.