trees with pointers to parents & memory gobbling

Colin Runciman colin@cs.york.ac.uk
Sat, 15 Jun 2002 12:10:19 +0100


This is a multi-part message in MIME format.
--------------050304090107090307050801
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

Hal Daume III wrote:

>I have a datatype which (simplified) looks like:
>
>data FBTree a = FBLeaf (Maybe (FBTree a)) a | FBBranch (Maybe (FBTree
>a)) (FBTree a) (FBTree a)
>
>is basically a tree with Maybe a parent node.  however, unlike the nice
>non-haskell equivalent, they tend to eat up memory as you traverse
>them.
>
Oh no they don't!  :-)

There is no space leak in the tree-traversal part of Hal's program, the 
problem
is that the program builds an iterated sequence of ever-deeper compositions
of findRoot and findLeftMostChild without demanding any of their results
until the very end of the sequence.

Quick plug: heap profiling showed me that the problem was with iterate;
the Hat tracing tools showed me that the tree traversal routines work fine.

I attach an amended version of Hal's program which does the 100000 down-up
traversals without leaking.

Regards
Colin R


--------------050304090107090307050801
Content-Type: text/plain;
 name="FBTree.hs"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="FBTree.hs"

data Tree a = Leaf a | Branch (Tree a) (Tree a) deriving (Eq, Show)

data FBTree a =
    FBLeaf (Maybe (FBTree a)) a 
  | FBBranch (Maybe (FBTree a)) (FBTree a) (FBTree a)

normalFBTree (FBLeaf _ _) = True
normalFBTree (FBBranch _ _ _) = True

instance Show a => Show (FBTree a) where
  showsPrec i = showsPrec i . unFBTree

mkFBTree = mkFBTree' Nothing
    where
    mkFBTree' par (Leaf a) = FBLeaf par a
    mkFBTree' par (Branch l r) = this
	where
        this = FBBranch par (mkFBTree' (Just this) l) (mkFBTree' (Just this) r)

unFBTree (FBLeaf _ a) = Leaf a
unFBTree (FBBranch _ l r) = Branch (unFBTree l) (unFBTree r)

findRoot (FBLeaf (Just par) _) = findRoot par
findRoot (FBBranch (Just par) _ _) = findRoot par
findRoot t = t

findLeftMostChild (FBBranch _ l _) = findLeftMostChild l
findLeftMostChild t = t

tree =
  Branch
    (Branch 
      (Branch
        (Branch
	  (Branch (Leaf 'h') (Branch (Leaf 'a') (Leaf 's')))
          (Leaf 'k'))
        (Branch (Leaf 'e') (Leaf 'l')))
      (Leaf 'l'))
    (Leaf '!')

fbtree = mkFBTree tree

updown n t | normalFBTree t =
  if n > 0 then updown (n-1) (findLeftMostChild (findRoot t))
  else t

main = print (updown 100000 fbtree)

--------------050304090107090307050801--