The standard trick that I learned from the wonderful Chris Okasaki, Purely functional data structures , should cache the results of costly operations on each node. for you to build a tree did not have to hurt. For example, when an expensive operation is depth, you can write:
module SizedTree (SizedTree, sizedTree, node, leaf, depth) where
data SizedTree = Node !Int SizedTree SizedTree | Leaf
node l r = Node (max (depth l) (depth r) + 1) l r
leaf = Leaf
depth (Node d _ _) = d
depth Leaf = 0
-- since we don't expose the constructors, we should
-- provide a replacement for pattern matching
sizedTree f v (Node _ l r) = f l r
sizedTree f v Leaf = v
Building SizedTreecosts O (1) additional work in each node (therefore, O (n) works to convert n-node Treeto SizedTree), but the gain is that checking the depth of a SizedTreeor any subtree is an O (1) operation.
source
share