Рассмотрим 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]
P.S. обратите внимание, что тип не может называться htree
, потому что имена типов в Haskell должны быть написаны с заглавной буквы. Вы можете заметить, что в последнем фрагменте я переименовал его в HTree
.
person
Fyodor Soikin
schedule
24.10.2019
there aren't a lot of online resources
Какой тип ресурса вы считаете наиболее полезным? Многие люди рекомендуют Learn you a Haskell. Это бесплатно онлайн. Вот глава о рекурсии: learnyouahaskell.com/recursion - person Garrison   schedule 24.10.2019