Рассмотрим Fork
. У него есть два поддерева, и у каждого из этих поддеревьев есть некоторая кодировка.
Допустим, что кодировка левого поддерева имеет вид:
[(x, pathToX), (y, pathToY)]
И, допустим, кодировка правого поддерева:
[(a, pathToA), (b, pathToB)]
Теперь, вы видите, какой должна быть кодировка всего форка? Должно быть так:
[(a, True : pathToA), (b, True : pathToB), (x, False : pathToX), (y, False : pathToY)]
Согласны ли вы с этим? Если нет, подумайте. Может быть, проработать несколько небольших примеров. Пока вы не согласитесь, что это так.
Видите, что я там делал? Я добавил False
к каждому пути в левом поддереве, а затем добавил True
к каждому пути в правом поддереве.
Давайте запишем это в синтаксисе Haskell:
encode (Fork left right) = prependToEach False (encode left) ++ prependToEach True (encode right)
Теперь вы, возможно, заметили, что я тут обманул: я использую функцию prependToEach
, которой не существует. Ну, неважно, давайте определимся!
prependToEach x list = map (prepend x) list
Видите? Добавление элемента к каждому элементу списка - это просто сопоставление функции добавления одного элемента над списком.
Но, конечно, я снова обманул: такой функции, как prepend
, пока нет. Так пусть будет один!
prepend x (a, path) = (a, x : path)
И вот, пожалуйста! Теперь осталось только определить базовый случай: каким должен быть путь Leaf
? Что ж, согласно приведенному вами примеру, у каждого Leaf
будет пустой путь, отражающий тот факт, что вам не нужно делать никаких ходов, чтобы добраться от этого листа к тому же листу:
encode (Leaf a) = [(a, [])]
А теперь, сложив все вместе:
encode :: HTree a -> [(a, [Bool])]
encode (Leaf a) = [(a, [])]
encode (Fork left right) = prependToEach False (encode left) ++ prependToEach True (encode right)
where
prependToEach x list = map (prepend x) list
prepend x (a, path) = (a, x : path)
И теперь, когда мы понимаем, как это было построено и почему, мы можем немного сократить его, используя списочные представления (хотя я очень сильно рассматриваю этот шагнеобязательно):
encode :: HTree a -> [(a, [Bool])]
encode (Leaf a) = [(a, [])]
encode (Fork left right) = [(x, False : p) | (x, p) <- encode left] ++ [(x, True : p) | (x, p) <- encode right]
PS обратите внимание, что тип не может быть назван htree
, потому что имена типов в Haskell должны быть заглавными. Вы можете заметить, что я переименовал его в HTree
в моем последнем фрагменте.