I'm working on a a function that check whether an element is part of a binary tree. I've defined a type for my tree called Tree, functions to get the root element and the left and right subtrees, and a function called isElement for checking whether a value is into my tree. Unfortunately, the function only works with the root element.
The following example illustrates the incorrect results I get from my isElement function:
*Main>let tree = Node 1 Empty (Node 2 Empty (Node 3 Empty Empty))
*Main> isElement tree 2
False
*Main> isElement tree 3
False
*Main> isElement tree 1
True
This is my code:
data Tree a = Node a (Tree a) (Tree a)
|Empty
deriving (Show)
nodeValue :: Tree t -> t
nodeValue (Node x _ _) = x
rightTree :: Tree t -> Tree t
rightTree (Node _ _ x) = x
leftTree :: Tree t -> Tree t
leftTree (Node _ x _) = x
isNode :: Tree t -> Bool
isNode (Node _ _ _) = True
isNode _ = False
isElement :: (Eq t) => Tree t -> t -> Bool
isElement tree t
|isNode tree == False = False
| nodeValue(tree) == t = True
| otherwise = (isElement (leftTree(tree)) t) || (isElement (leftTree(tree)) t)
There is a mistake in the definition of your isElement function: you're calling leftTree twice, instead of calling both leftTree and rightTree. As a result, right subtrees are never explored. Amend the code accordingly,
isElement tree t
|isNode tree == False = False
| nodeValue(tree) == t = True
| otherwise = (isElement (leftTree(tree)) t) || (isElement (rightTree(tree))
and then isElement works as advertised:
λ> let tree = Node 1 Empty (Node 2 Empty (Node 3 Empty Empty))
λ> isElement tree 2
True
λ> isElement tree 3
True
λ> isElement tree 1
True
However, there is still room for improvement. You don't really need all those functions (isNode, nodeValue, etc.) to define isElement. Instead, you can do all that unpacking with pattern matching, by breaking down the definition into two equations: one corresponding to the case where the tree is empty, and another corresponding to the case where the tree is a node:
isElement :: (Eq a) => Tree a -> a -> Bool
isElement Empty _ = False
isElement (Node v l r) x = v == x || isElement l x || isElement r x
Edit: as pointed out by Luis Casillas in his comment, an additional benefit of this alternative definition is that it lends itself better (than the original definition) to exhaustiveness checking by the compiler.
Related
I have a typical binary search tree data type:
data Tree a
= Empty
| Branch a (Tree a) (Tree a) deriving Show
and a catamorphism
foldt :: b -> (a -> b -> b -> b) -> Tree a -> b
foldt empty _ Empty = empty
foldt empty branch (Branch a l r) = branch a (foldt empty branch l) (foldt empty branch r)
I tried to define an insert function using foldt and got some interesting results:
insert :: (Ord a) => a -> Tree a -> Tree a
insert x = foldt (single x) insertb
where insertb a left right
| x == a = Branch x left right
| x < a = Branch a (insert x left) right
| x > a = Branch a left (insert x right)
ghci> mytree = insert 2 (Branch 3 Empty Empty)
ghci> mytree
Branch 3 (Branch 2 (Branch 2 Empty Empty) (Branch 2 Empty Empty)) (Branch 2 Empty Empty)
ghci>
Of course, a traditional insert method behaves as expected:
insert' :: (Ord a) => a -> Tree a -> Tree a
insert' x Empty = single x
insert' x (Branch a left right)
| x == a = Branch x left right
| x < a = Branch a (insert' x left) right
| x > a = Branch a left (insert' x right)
ghci> mytree2 = insert' 2 (Branch 3 Empty Empty)
ghci> mytree2
Branch 3 (Branch 2 Empty Empty) Empty
ghci>
Is there a way to define insert in terms of foldt, or am I barking up the wrong tree (ha) here?
Let's define a function
insertMaybe :: Ord a => Tree a -> Maybe a -> Tree a
This function takes a tree, and maybe an element. In the Just case, the element is inserted. In the Nothing case, the tree is returned unchanged. So then we can define
insert a t = insertMaybe t (Just a)
Now:
insertMaybe :: Ord a => Tree a -> Maybe a -> Tree a
insertMaybe = foldt leaf branch
where
leaf (Just new) = ?
leaf Nothing = ?
branch a l r Nothing = ?
branch a l r (Just new)
| ... = ?
...
Alternatively:
data Ins a = Ins
{ inserted :: Tree a
, notInserted :: Tree a }
insert a t = inserted (insertAndNot a t)
-- Return the tree with the
-- element inserted, and also unchanged.
insertAndNot :: Ord a => a -> Tree a -> Ins a
insertAndNot new = foldt leaf branch
where
leaf = Ins ? ?
branch a ~(Ins li lni) ~(Ins ri rni)
| ... = Ins ? ?
...
Paramorphism
The above solutions have a major efficiency problem: they completely rebuild the tree structure just to insert an element. As amalloy suggested, we can fix that by replacing foldt (a catamorphism) by parat (a paramorphism). parat gives the branch function access to both the recursively modified and the unmodified subtrees.
parat :: b -> (a -> (Tree a, b) -> (Tree a, b) -> b) -> Tree a -> b
parat leaf _branch Empty = leaf
parat leaf branch (Branch a l r) =
branch a
(l, parat leaf branch l)
(r, parat leaf branch r)
Conveniently, it's also slightly easier to define insert using parat. Can you see how? This ends up being an efficient version of the "alternative" way I suggested for using foldt.
Thanks to dfeuer and amalloy for the tips on paramorphisms, TIL!
Given a paramorphism for the Tree data type:
parat :: b -> (a -> (Tree a, b) -> (Tree a, b) -> b) -> Tree a -> b
parat empty _ Empty = empty
parat empty branch (Branch a l r) =
branch a
(l, parat leaf branch l)
(r, parat leaf branch r)
we can write an insert function as:
insert :: Ord a => a -> Tree a -> Tree a
insert x = parat (single x) branch
where branch a (l, l') (r, r')
| x == a = Branch x l r
| x < a = Branch a l' r
| x > a = Branch a l r'
ghci> mytree = insert 2 (Branch 3 Empty Empty)
ghci> mytree
Branch 3 (Branch 2 Empty Empty) Empty
ghci>
testing a bigger tree...
import Data.Function
mytree :: Tree Integer
mytree = (Branch 3 Empty Empty) & insert 2 & insert 4 & insert 6 & insert 5 & insert 10
inorder :: Tree a -> [a]
inorder = foldt [] (\a l r -> l ++ [a] ++ r)
ghci> mytree
Branch 3 (Branch 2 Empty Empty) (Branch 4 Empty (Branch 6 (Branch 5 Empty Empty) (Branch 10 Empty Empty)))
ghci> inorder mytree
[2,3,4,5,6,10]
ghci>
I m trying to create a function which check the whether a given value is in a tree, this what a got so far
data Tree = Null |
Node Int Tree Tree
deriving (Show)
testTree = Node 20 (Node 3 (Node 12 Null Null) (Node 7 Null Null))
(Node 8 (Node 4 (Node 6 Null Null) Null) Null)
isMember :: Int->Tree -> Bool
isMember x (Null) = False
isMember x(Node n st1 st2) = x == n
It didn't give me any error but I wanted to check the subtree as well
You just need to call isMember recursively on each subtree, as needed.
isMember :: Int -> Tree -> Bool
isMember x Null = False
isMember x (Node n st1 st2) = x == n || isMember x st1 || isMember x st2
You can make Tree a polymorphic type and make it an instance of Foldable. With the DeriveFoldable extension [ghc-doc], then you can make use of elem :: (Eq a, Foldable f) => a -> f a -> Bool to find out if the tree contains a given element:
{-# LANGUAGE DeriveFoldable #-}
data Tree a
= Null
| Node a (Tree a) (Tree a)
deriving (Foldable, Show)
Then your isMember is thus a special case of elem:
isMember :: Int -> Tree Int -> Bool
isMember = elem
For example:
Prelude> elem 5 testTree
False
Prelude> elem 20 testTree
True
Prelude> elem 4 testTree
True
Prelude> elem 7 testTree
True
Prelude> elem 9 testTree
False
I am trying to check out if tree is a subtree of another tree. Here is my data for Tree:
data Tree a = Empty | Node a (Tree a)(Tree a) deriving Show
tree1 :: Tree Int
tree1 = Node 1
(Node 2
(Node 4 Empty Empty)
(Node 5 Empty
(Node 8 Empty Empty))
)
(Node 3
(Node 6 Empty
(Node 9 Empty Empty))
(Node 7 Empty Empty)
)
tree2 :: Tree Int
tree2 = Node 2
(Node 4 Empty Empty)
(Node 5 Empty
(Node 8 Empty Empty))
And finally def of unfulfilled function:
isSubTree :: Eq a => Tree a -> Tree a -> Bool
isSubTree _ Empty = False
isSubTree Empty _ = False
isSubTree (Node a l r) (Node b ll rr) |
| otherwise = False
I need a hint how to fulfill first guardian - should i use elem or any other basic function? If I would want to find any specific element in tree I would use code below, so should I somehow modify that code?
treeMember x (Node a l r) |x `elem` [a] = True
|otherwise = treeMember x l || treeMember x r
A tree t1 is a (non-strict) subtree of a tree t2 given the two trees are equal, or t1 is a subtree of one of the (direct) children of t2.
We can let Haskell implement an instance for the Eq typeclass with:
data Tree a = Empty | Node a (Tree a) (Tree a) deriving (Eq, Show)
So now we can implement a check with:
isSubtree :: Eq a => Tree a -> Tree a -> Bool
isSubtree t1 t2 | t1 == t2 = True
isSubtree t1 (Node _ c1 c2) = …
isSubtree _ _ = False
where you still need to fill in the … part. I leave this as an exercise.
is there any way to solve this problem with incorrect indentation ? I want to check if every node on a given tree is bigger than it's grandfather (if it has one).
I've written a function that gives all nodes on every level and the idea in the main function is to compare the nodes if they are smaller than their grandchildren.
data BTree = Empty | Node Int BTree Btree
grandchildrenIncreased :: BTree -> Bool
grandchildrenIncreased Empty = Empty
grandchildrenIncreased BTree = func BTree level
where f BT n
| head (level BT n) < head (level BT n+2) = tail (level BT 1)
(level BT n+2) grandchildrenIncreased f BT (n+1)
| length (level BT n) == 0 = True
| otherwise = False
level :: BTree -> Int -> [a]
level Empty _ = []
level (Node n lt rt) 1 = [n]
level (Node _ lt rt) k
= (level lt (k-1)) ++ (level rt (k-1))
It gives error on the whole line where "tail" is.
It is usually better to use pattern matching. By using pattern matching, the compiler can warn you if you did not cover all possible patterns, and hence it is less likely that your program will error.
That being said, your current attempt has a lot of problems, and not only with indentation.
Your grandchildrenIncreased does not seem to make much sense if we look at the types. For example you write grandchildrenIncreased Empty = Empty, but the result type is a Bool, so it should be True or False.
You also mix type constructors (like BTree) with data constructors. For example your second line grandchildrenIncreased BTree = func BTree level makes not much sense either, since BTree is a type, it is not a specific pattern for tree values.
You also seem to use level in your grandchildrenIncreased to refer both to the level :: BTree -> Int -> [a] function, as well as to some non-existing Int value.
Finally by first converting the tree to lists of levels, you lose the structure of which node is connected to which grandparent, making it hard to check that.
grandchildrenIncreased :: BTree -> Bool
grandchildrenIncreased Empty = True
grandchildrenIncreased n#(Node v l r) =
all (v <) (level n 3) && grandchildrenIncreased l && grandchildrenIncreased r
We thus check in the case of a Node v l r, if all the values of the level underneath the subtrees l and r are all larger than v, and that the condition also holds for the l and r subtree.
Note that since you constructed a tree of Ints, the most generic type signature for level is:
level :: BTree -> Int -> [Int]
level Empty _ = []
level (Node n lt rt) 1 = [n]
level (Node _ lt rt) k = (level lt (k-1)) ++ (level rt (k-1))
Here it might however be more useful to define a children function:
children :: BTree -> [BTree]
children Empty = []
children (Node _ lt rt) = [lt, rt]
and a way to extract the value of a Node:
treeVal :: BTree -> Maybe Int
treeVal Empty = Nothing
treeVal (Node v _ _) = Just v
then we can derive the values with:
import Data.Maybe(catMaybes)
grandchildrenIncreased :: BTree -> Bool
grandchildrenIncreased Empty = True
grandchildrenIncreased n#(Node v l r) =
all (v <) (catMaybes (treeVal <$> (children n >>= children))) &&
grandchildrenIncreased l && grandchildrenIncreased r
I have to write a recursive function that, Given a Tree
datatype,will return the depth of the tree. An empty tree should return
0. A single root node Tree should return 1.
expected output:
let treeCons x = (\x -> foldl (flip insertTree) Empty x) x
depth (treeCons []) -> 0
depth (treeCons [5,4,6,3,7,1]) -> 4
depth (treeCons [1,2,5,8,9,4,7]) -> 5
depth (treeCons [5,4,6,3,7,1,2,5,8,9,4,7,8,5,3,4]) -> 6
I wrote the following datatype and insert function:
data Tree a = Node a (Tree a) (Tree a) | Empty deriving (Show, Eq)
insertTree :: (Ord a) => a -> Tree a -> Tree a
insertTree a Empty = Node a Empty Empty
insertTree a (Node b Empty Empty) = if (a <= b) then (Node b (Node a Empty Empty) Empty) else (Node b Empty (Node a Empty Empty))
insertTree a (Node b left right) = if (a <= b) then (Node b (insertTree a left) right ) else (Node b left (insertTree a right))
However, I'm not getting how to write depth function.I'm very new in haskell and I'll appreciate if someone helps me.
An empty tree has depth 0, and a node has depth 1 plus the maximum depth of its child nodes:
depth :: Tree a -> Int
depth Empty = 0
depth (Node _ l r) = 1 + max (depth l) (depth r)
Here you go, is very simple, recursing through a list and a Tree is about the same, only the data types differ. Where you add 1 every time you hit a branch of the tree in question:
tDepth :: Tree a -> Int
tDepth Empty = 0
tDepth (Node _ left right) = 1 + max (tLength left) (tLength right)