Я пишу программу, пытаясь реализовать игрушечный процессор XML.Прямо сейчас программа должна прочитать поток событий (например, SAX), описывающий структуру документа, и лениво построить соответствующее дерево.
События определяются следующим типом данных:
data Event = Open String
| Close
Тогда возможный ввод:
[Open "a", Open "b", Close, Open "c", Close, Close]
, который будет соответствовать дереву:
a
/ \
b c
Я бы хотел сгенерировать дерево ленивым образом, чтобыон не должен присутствовать в памяти в полной форме в любое время.Моя текущая реализация, однако, похоже, имеет утечку пространства, в результате чего все узлы сохраняются, даже когда они больше не нужны.Вот код:
data Event = Open String
| Close
data Tree a = Tree a (Trees a)
type Trees a = [Tree a]
data Node = Node String
trees [] = []
trees (Open x : es) =
let (children, rest) = splitStream es
in (Tree (Node x) (trees children)) : (trees rest)
splitStream es = scan 1 es
scan depth (s@(Open {}) : ss) =
let (b, a) = scan (depth+1) ss
in (s:b, a)
scan depth (s@Close : ss) =
case depth of
1 -> ([], ss)
x -> let (b, a) = scan (depth-1) ss
in (s:b, a)
getChildren = concatMap loop
where
loop (Tree _ cs) = cs
main = print .
length .
getChildren .
trees $
[Open "a"] ++ (concat . replicate 1000000 $ [Open "b", Close]) ++ [Close]
Функция trees
преобразует список событий в список Tree Node
.getChildren
собирает все дочерние узлы (помеченные буквой "b") корня ("a").Затем они подсчитываются и выводится полученное число.
Скомпилированная программа, созданная с использованием GHC 7.0.4 (-O2), продолжает увеличивать использование памяти до того момента, когда она печатает число узлов.С другой стороны, я ожидал почти постоянного использования памяти.
Глядя на профиль кучи "-hd", становится ясно, что большая часть памяти занята конструктором списка (:
),Похоже, что один из списков, созданных scan
или trees
, сохраняется полностью.Однако я не понимаю, почему length . getChildren
должен избавляться от дочерних узлов, как только они пройдены.
Есть ли способ исправить такую утечку пространства?