Search code examples
functionsortinghaskellfunctional-programmingbinary-tree

Fixing a function checking whether the input binary tree is ordered


I have the following algebraic data type:

data Tree a = Empty | Node a (Tree a) (Tree a)
  deriving (Show, Eq)

Also, I have this code snippet:

fromJust :: Maybe a -> a
fromJust (Just val) = val
fromJust Nothing = error "Cannot unpack Nothing."

getTreeMinimum :: Ord a => Tree a -> Maybe a
getTreeMaximum :: Ord a => Tree a -> Maybe a

getTreeMaximum Empty = Nothing
getTreeMaximum (Node value l r) =
  if l == Empty && r == Empty then Just value else
  if l == Empty && r /= Empty then if value < fromJust (getTreeMinimum r) then (getTreeMaximum r) else
  if l /= Empty && r == Empty then if fromJust (getTreeMaximum l) < value then Just (value) else
  if l /= Empty && r /= Empty then if fromJust (getTreeMaximum l) < value && value < fromJust (getTreeMinimum r) then (getTreeMaximum r) else Nothing

getTreeMinimum Empty = Nothing
getTreeMinimum (Node value l r) = 
  if l == Empty && r == Empty then Just value else
  if l == Empty && r /= Empty then if value < fromJust (getTreeMinimum r) then Just (value) else
  if l /= Empty && r == Empty then if fromJust (getTreeMaximum l) < value then (getTreeMinimum l)
  if l /= Empty && r /= Empty then if fromJust (getTreeMaximum l) < value && value < fromJust (getTreeMinimum r) then (getTreeMinimum l) else Nothing

isOrderedHelper :: Ord a => Tree a -> Bool
isOrderedHelper Empty = True

isOrderedHelper (Node nodeValue leftChild Empty) = if isOrderedHelper leftChild == False then False else (fromJust (getTreeMaximum leftChild)) < nodeValue

isOrderedHelper (Node nodeValue Empty rightChild) = if isOrderedHelper rightChild == False then False else nodeValue < fromJust ((getTreeMinimum rightChild))

isOrderedHelper (Node nodeValue leftChild rightChild) =
  if isOrderedHelper leftChild == False || isOrderedHelper rightChild == False
  then False 
  else fromJust (getTreeMaximum leftChild) < nodeValue && nodeValue < fromJust (getTreeMinimum rightChild)

isOrdered :: Ord a => Tree a -> Bool
isOrdered Empty = True
isOrdered tree = isOrderedHelper tree

The above gives me:

error: parse error on input 'getTreeMinimum'
    getTreeMinimum Empty = Nothing
    ^^^^^^^^^^^^^^
Failed, no modules loaded.

I have two questions (the second one is optional):

  1. How to fix the compile time error?
  2. Is it possible to improve the efficiency of the function in question?

Solution

  • Since if is an expression in Haskell each if has to have exatly one then and one else but this

    getTreeMaximum (Node value l r) =
      if l == Empty && r == Empty then Just value else
      if l == Empty && r /= Empty then if value < fromJust (getTreeMinimum r) then (getTreeMaximum r) else
      if l /= Empty && r == Empty then if fromJust (getTreeMaximum l) < value then Just (value) else
      if l /= Empty && r /= Empty then if fromJust (getTreeMaximum l) < value && value < fromJust (getTreeMinimum r) then (getTreeMaximum r) else Nothing
    

    has 7 if and 7 then but only 4 else

    I would probably write that using pattern matching to avoid such a deeply nested if tree:

    getTreeMaximum (Node value Empty Empty) = Just value
    getTreeMaximum (Node value Empty r) = if value < fromJust (getTreeMinimum r) then (getTreeMaximum r) else Nothing
    getTreeMaximum (Node value l Empty) = if fromJust (getTreeMaximum l) < value then Just (value) else Nothing
    getTreeMaximum (Node value l r) = if fromJust (getTreeMaximum l) < value && value < fromJust (getTreeMinimum r) then (getTreeMaximum r) else Nothing
    

    But I don't think the clauses other than the getTreeMaximum Empty have any reason to return Nothing at all since there's always a value, so you'll have to adjust these.