Is it something wrong with my haskell formatting?
No, it is a semantical error. You write:
(isBST l) < h
So this means you ask Haskell to determine whether l
is a binary search tree, which is True
or False
, but you can not compare True
or False
with h
. Even if you could (some languages see True
as 1
and False
as 0
), then it would still be incorrect, since we want to know whether all nodes in the left subtree are less than h
.
So we will somehow need to define bounds. A way to do this is to pass parameters through the recursion and perform checks. A problem with this is that the root of the tree for example, has no bounds. We can fix this by using a Maybe Int
is a boundary: if it is Nothing
, the boundary is "inactive" so to speak, if it is Just b
, then the boundary is "active" with value b
.
In order to make this check more convenient, we can first write a way to check this:
checkBound :: (a -> a -> Bool) -> Maybe a -> a -> Bool
checkBound _ Nothing _ = True
checkBound f (Just b) x = f b x
So now we can make a "sandwich check" with:
sandwich :: Ord a => Maybe a -> Maybe a -> a -> Bool
sandwich low upp x = checkBound (<) low x && checkBound (>) upp x
So sandwich
is given a lowerbound and an upperbound (both Maybe a
s), and a value, and checks the lower and upper bounds.
So we can write a function isBST'
with:
isBST' :: Maybe Int -> Maybe Int -> Tree -> Bool
isBST' low upp ... = ....
There are two cases we need to take into account: the Leaf x
case, in which the "sandwich constraint" should be satisfied, and the Node h l r
case in which h
should satisfy the "sandwich constraint" and furthermore l
and r
should satsify different sandwhich constraints. For the Leaf x
it is thus like:
isBST' low upp (Leaf x) = sandwich low upp x
For the node case, we first check the same constraint, and then enforce a sandwich between low
and h
for the left part l
, and a sandwich between h
and upp
for the right part r
, so:
isBST' low upp (Node h l r) = sandwich low upp h &&
isBST' low jh l &&
isBST' jh upp r
where jh = Just h
Now the only problem we still have is to call isBST'
with the root element: here we use Nothing
as intial bounds, so:
isBST :: Tree -> Bool
isBST = isBST' Nothing Nothing
There are of course other ways to enforce constraints, like passing and updating functions, or by implement four variants of the isBST'
function that check a subset of the constraints.
isBST l < h
- what type ish
and what isisBST l
, I think you need to make your 2nd line a bit more complex,isBST l &&isBST r &&...
. – epsilonhalbeif x then True else False
is justx
. – n. 1.8e9-where's-my-share m.the left subtree must always contain only nodes less than the head
and how do you express this condition? – n. 1.8e9-where's-my-share m.