1
\$\begingroup\$

Given the following Abstact Data Type:

data Tree a = Leaf
 | Node Integer (Tree a) a (Tree a) 
 deriving (Show, Eq)-- where Integer is the height (bottom = 0)

I wrote a function to get a tree's height.

-- Get the height of a tree.
getTreeHeight :: Tree a -> Integer
getTreeHeight Leaf = 0
getTreeHeight (Node _ left _ right) = 1 + max (getTreeHeight left) (getTreeHeight right)

Please critique this implementation. In particular, I'm curious if I could've written this with a fold-ing function instead. However, I'm not sure if that would require Tree to have implemented the Foldable typeclass.

Petr
3,06018 silver badges33 bronze badges
asked Oct 4, 2014 at 17:18
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

First, you should decide if the height of a tree will be a field of Node or not. If yes, then there is no need to compute it. Instead, your tree module should hide the constructors and only expose smart constructors:

data Tree a = Leaf
 | Node Integer (Tree a) a (Tree a) 
 deriving (Show, Eq)-- where Integer is the height (bottom = 0)
getTreeHeight :: Tree a -> Integer
getTreeHeight Leaf = 0
getTreeHeight (Node h _ _ _) = h
leaf :: Tree a
leaf = Leaf
node :: Tree a -> a -> Tree a -> Tree a
node l x r = Node (1 + max (getTreeHeight l) (getTreeHeight r)) l x r

In this case, getTreeHeight just accesses the pre-computed height.


Or you might want to keep Node without the height, and compute it separately. Implementing Foldable won't help, as it only exposes the elements of a data structure, while you need to examine the structure, not the elements.

What you can do is to create a generalized folding function over Tree, so called catamorphism, which allows you to express functions that consume trees:

data Tree a = Leaf
 | Node (Tree a) a (Tree a) 
 deriving (Show, Eq)-- where Integer is the height (bottom = 0)
treeFold :: (r -> a -> r -> r) -> r -> Tree a -> r
treeFold f z = h
 where
 h Leaf = z
 h (Node l x r) = f (h l) x (h r)
{-# INLINE treeFold #-}
-- Get the height of a tree.
getTreeHeight :: Tree a -> Integer
getTreeHeight = treeFold (\l _ r -> 1 + max l r) 0

Function treeFold allows you to express all kinds of other functions, to give a few examples:

-- Get the size of a tree.
getTreeSize :: Tree a -> Integer
getTreeSize = treeFold (\l _ r -> 1 + l + r) 0
-- Get the number of leaves.
getTreeLeaves :: Tree a -> Integer
getTreeLeaves = treeFold (\l _ r -> l + r) 1
answered Oct 4, 2014 at 19:04
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.