52700.fb2
(*)
a
Zero
= ...
(*)
a
(Succ b)
= ...
48 | Глава 3: Типы
Декомпозицию можно проводить в аргументах функции. Там мы видим строчную запись дерева, в узлах
стоят конструкторы (начинаются с большой буквы), переменные (с маленькой буквы) или символ безразлич-
ной переменой (подчёркивание).
С помощью конструкторов, мы указываем те части, которые обязательно должны быть в дереве для дан-
ного уравнения. Так уравнение
not True
= ...
сработает, только если на вход функции поступит значение True. Мы можем углубляться в дерево значе-
ния настолько, насколько нам позволят типы, так мы можем определить функцию:
is7 :: Nat -> Bool
is7
(Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))
= True
is7
_
= False
С помощью переменных мы даём синонимы поддеревьям. Этими синонимами мы можем пользоваться в
правой части функции. Так в уравнении
addZero (a:[])
мы извлекаем первый элемент из списка, и одновременно говорим о том, что список может содержать
только один элемент. Отметим, что если мы хотим дать синоним всему дереву а не какой-то части, мы просто
пишем на месте аргумента переменную, как в случае функции xor:
xor a b = ...
С помощью безразличной переменной говорим, что нам не важно, что находится у дерева в этом узле.
Уравнения в определении синонима обходятся сверху вниз, поэтому часто безразличной переменной поль-
зуются в смысле “а во всех остальных случаях”, как в:
instance Eq Nat where
(==) Zero
Zero
= True
(==) (Succ a) (Succ b) = a == b
(==) _
_
= False
Переменные и безразличные переменные также могут уходить вглубь дерева сколь угодно далеко (или
ввысь дерева, поскольку первый уровень в строчной записи это корень):
lessThan7 :: Nat -> Bool
lessThan7
(Succ (Succ (Succ (Succ (Succ (Succ (Succ _)))))))
= False