Учебник по Haskell | страница 46
тельно у нас был лишь один конструктор Name.
Имена конструкторов должны быть уникальными в пределах модуля. У нас нет таких двух типов, у ко-
торых совпадают конструкторы. Это говорит о том, что по имени конструктора компилятор знает значение
какого типа он может построить.
Произведение типов состоит из конструктора, за которым через пробел идут подтипы. Такая структура
не случайна, она копирует структуру функции. В качестве имени функции выступает конструктор, а в ка-
честве аргументов – значения заданных в произведении подтипов. Функция-конструктор после применения
“оборачивает” значения аргументов и создаёт новое значение. За счёт этого мы могли бы определить типы
по-другому. Мы могли бы определить их в стиле классов типов:
data Bool where
True
:: Bool
False :: Bool
Мы видим “класс” Bool, у которого два метода. Или определим в таком стиле Nat:
data Nat where
Zero
:: Nat
Succ
:: Nat -> Nat
Мы переписываем подтипы по порядку в аргументы метода. Или определим в таком стиле списки:
data [a] where
[]
:: [a]
(:)
:: a -> [a] -> [a]
Конструктор пустого списка [] является константой, а конструктор объединения элемента со списком
(:), является функцией. Когда я говорил, что типы определяют примитивы и методы составления из прими-
тивов, я имел ввиду, что некоторые конструкторы по сути являются константами, а другие функциями.
Эти “методы” определяют базовые значения типа, все другие значения будут комбинациями базовых.
При этом сумма типов, определяет число методов “классе” типа, то есть число базовых значений, а произ-
ведение типов в каждой альтернативе определяет имя метода (именем конструктора) и состав аргументов
(перечислением подтипов).
3.2 Структура констант
Мы уже знаем, что значения могут быть функциями и константами. Объявляя константу, мы даём имя-
синоним некоторой комбинации базовых конструкторов. В функции мы говорим как по одним значениям
получить другие. В этом и следующем разделе мы посмотрим на то, как типы определяют структуру констант
и функций.
Давайте присмотримся к константам:
Succ (Succ Zero)
Neg (Add One (Mul Six Ten))
Not (Follows A (And A B))
Cons 1 (Cons 2 (Cons 3 (Cons 4 Nil)))
Заменим все функциональные конструкторы на букву f (от слова function), а все примитивные конструк-
торы на букву c (от слова constant).
f (f c)
f (f c (f c c))
f (f c (f c c))
f c (f c (f c (f c c)))
Те кто знаком с теорией графов, возможно уже узнали в этой записи строчную запись дерева. Все зна-
чения в Haskell являются деревьями. Узел дерева содержит составной конструктор, а лист дерева содержит