В самом деле, вы можете задать для Tree параметр типа, как в Александр Полуэктов .Достаточно просто!Но зачем останавливаться на достигнутом?Мы можем получить немного больше удовольствия, чем просто это.Вместо просто рекурсивной структуры с полиморфными данными , вы можете сделать структуру полиморфной в самой рекурсии !
Во-первых, абстрагируйте ссылки дерева на себя, втак же, как абстрагирование ссылок на Int
, замена рекурсивных ссылок новым параметром t
.Это оставляет нам довольно расплывчатую структуру данных:
data TNode t a = Empty
| Leaf a
| Node (t a) a (t a)
deriving (Eq, Ord, Show, Read)
Это было переименовано здесь как TNode
, потому что это больше не дерево;просто простой тип данных.Теперь, чтобы восстановить исходную рекурсию и создать дерево, мы вращаем TNode
и подаем его себе:
newtype Tree a = Tree (TNode Tree a) deriving (Eq, Ord, Show, Read)
Теперь мы можем использовать это Tree
рекурсивно, хотя, к сожалению, за счет некоторыхлишнее словоблудие, вот так:
Tree (Node (Tree Empty) 5 (Tree (Leaf 2)))
Так что же это дает нам, кроме дополнительного набора текста, спросите вы?Просто то, что мы отделили структуру фундаментального дерева как от содержащихся в ней данных, так и от метода, с помощью которого эти данные конструируются и обрабатываются, что позволяет нам писать более общие функции для работы с тем или иным аспектом.
Например, мы можем украсить деревья дополнительными данными или скомбинировать дополнительные элементы в дерево, не влияя на какие-либо общие функции дерева.Скажем, мы хотели дать имя каждому фрагменту дерева:
newtype NameTree a = NameTree (String, TNode NameTree a) deriving (Eq, Ord, Show, Read)
С другой стороны, мы можем написать общую логику обхода дерева:
toList f t = toList' f (f t) []
where toList' f (Node t1 x t2) xs = toList' f (f t1) (x : toList' f (f t2) xs)
toList' f (Leaf x) xs = x:xs
toList' _ Empty xs = xs
Учитывая функцию для извлечениятекущий TNode
из рекурсивного дерева, мы можем использовать его для любой такой структуры:
treeToList = toList (\(Tree t) -> t)
nameTreeToList = toList (\(NameTree (_, t)) -> t)
Конечно, это, вероятно, выходит далеко за рамки того, что вы хотите сделать, но это хороший вкуснасколько полиморфизм и универсальный код Haskell позволяет (нет, поощряет) программист создавать.