Прежде всего определение типа данных должно содержать не вопросительные знаки, а обычные буквы:
data Tree a = Leaf a | Fork a (Tree a) (Tree a)
Определяет тип Tree
, который содержит элементы некоторого не указанного типа a
.
Это либо дерево Leaf
, содержащее элемент типа a
, либо дерево Fork
, содержащее также элемент типа a
и два поддерева. Поддеревья - это Tree
структуры, которые содержат элементы типа a
.
Важно отметить, что Haskell использует круглые скобки исключительно для группировки, как в 2 * (2+3)
, а не для указания вызывающих функций. Для вызова функций параметры просто пишутся после имени функции, разделяются пробелами, как в sin 30
или compare "abc" "abd"
.
В операторе case
часть слева от ->
- это совпадение с шаблоном, часть справа - результат функции, если дерево действительно имеет форму, указанную слева. Шаблон Fork q (Fork p a b) c
совпадает, если дерево является Fork
(это Fork
из определения типа данных), а его первое поддерево является другим Fork
. Строчные буквы - это всего лишь переменные, фиксирующие совпадение различных частей древовидной структуры. Таким образом, p
будет элементом, содержащимся в поддереве, a
будет первой ветвью поддеревьев и b
второй.
Правая сторона ->
, Fork p a (Fork q b c)
, теперь строит новое дерево из этих частей, сопоставленных в сопоставлении с образцом. Переменные в нижнем регистре - это все совпадающие слева части дерева, а Fork
- конструкторы из определения типа данных. Он строит дерево, которое является Fork
и имеет второе поддерево, которое также является Fork
(часть в скобках). Остальные части этого дерева - это только те части дерева, которые были «распущены» на левой стороне.