Примечание: Это сообщение написано грамотным Haskell. Скопируйте его в свой любимый редактор, сохраните его как Tree.lhs или аналогичный и загрузите в GHCi.
Давайте попробуем немного другой подход. Вместо того чтобы показывать дерево в виде одной строки, мы создаем линии нашей строки:
> data Tree a b = Branch b (Tree a b) (Tree a b) | Leaf a
> instance (Show a, Show b) => Show (Tree a b) where
> show tree = magic (go tree)
> where
> go :: (Show a, Show b) => Tree a b -> [String]
Не беспокоиться еще о magic
, это будет иметь тип magic :: [String] -> String
. Прежде всего сосредоточимся на go
. Если мы хотим показать одну Leaf
, мы должны только касаться одного значения:
> go (Leaf v) = [show v]
Теперь о филиалах и их отступа. Мы можем показать значение, как и в случае Leaf
:
> go (Branch v l r) = show v
, но мы должны убедиться, что фактические ветви имеют правильное количество пробелов впереди. Мы используем функцию (пока не определено) называется indent
:
> : indent (go l ++ go r)
Теперь у нас есть почти все на месте: если indent
делает то, что предполагает его название, он собирается отступа все строки в [String]
возвращенного go l ++ go r
на одно место. Поэтому ветви дерева всегда будут иметь еще одно пространство спереди, как сам корень.Все, что не хватает теперь indent
и magic
:
> indent :: [String] -> [String]
> indent = map (' ':)
Это было довольно легко. Конечно, вы можете обменять (' ':)
с чем-то еще.
Это работа magic
, чтобы взять все струны и приклеить их вместе. Так как вы хотите, чтобы отступы всего дерева на одном пространстве, давайте использовать indent
в последний раз:
> magic = unlines . indent
И это все. Вот весь код для лучшего обзора:
instance (Show a, Show b) => Show (Tree a b) where
show tree = magic (go tree)
where
go (Leaf v) = [show v]
go (Branch v l r) = show v : indent (go l ++ go r)
indent = map (' ':)
magic = unlines . indent
Хорошая часть об этой технологии является то, что мы никогда не должны использовать явные уровни или указать количество пространств где-то. Мы можем просто прогуляться по дереву, создать наш [String]
и иметь magic
и indent
сделать остальное для нас.
Подождите. Это действительно скомпилировалось? Вам не хватает отступов строк 'show'. – Zeta
Тот факт, что вы явно говорите, что не используете 'Data.Tree', говорит о том, что вы уже знаете о' drawTree'. Я могу понять, почему вы, возможно, захотите не смотреть на источник «drawTree» при создании своего собственного решения: ради радости изобретать идеи самостоятельно. Поэтому я не могу понять, почему вы попросите решение из других источников. Что лучше изучать идеи от какого-то случайного человека на StackOverflow по сравнению с изучением идей от автора пакета 'container'? –
Это не хороший экземпляр «Show». Обычно вы должны копировать результат 'show' и использовать его как исходный код Haskell (возможно, с добавлением аннотаций типа). Это было бы лучше как независимая функция showTree. – dfeuer