Relationships in a Tree (Haskell) - haskell

Binary trees with values in the leaves and nodes are defined by:
data Tree a = Leaf a
| Node a (Tree a) (Tree a)
deriving (Eq, Show)
For example,
10
/ \
/ \
8 2
/ \ / \
3 5 2 0
exTree :: Tree Int
exTree = N 10 (N 8 (H 3) (H 5))
(N 2 (H 2) (H 0))
Well, I need a function called RelationshipBinaryTree, which generates a list of tuples, whose first component is an x and its second the father. In this tree,
relationshipBinaryTree :: Tree a -> [(a,a)]
relationshipBinaryTree exTree = [(10,8),(8,3),(8,5),(10,2),(2,2),(2,0)]
Also, I need to define it in the Data.Tree hackage (https://hackage.haskell.org/package/containers-0.5.11.0/docs/Data-Tree.html)
I hope you can help me because I don't understand trees and graphs very well.
I have tried this
relationshipBinaryTree :: Tree a -> [(a,a)]
relationshipBinaryTree (L _) = []
relationshipBinaryTree (N _ (Tree i) (Tree d)) = relationshipBinaryTree (N _) ++ relationshipBinaryTree (Tree i) ++ relationshipBinaryTree (Tree d)

You want to use Data.Tree, but Data.Tree isn't even about binary trees, but about multi way trees (a.k.a. rose trees). However, if you had a function value :: Tree a -> a, then of course you could map it to the children of a rose tree and combine the result with the value.
Now, there exists a function that does that in Data.Tree, it's called rootLabel. And there is another function to geht the children of a node, it's called subForest.
That comes from the definition of Tree in Data.Tree:
Node
rootLabel :: a -- label value
subForest :: Forest a -- zero or more child trees
So we could define for rose trees:
fatherChild :: Tree a -> [(a, a)]
fatherChild t = map mkPair children ++ concatMap fatherChild children
where mkPair child = (rootLabel t, child)
children = subForest t
Example:
fatherChild (Node 3 [Node 8 [], Node 4 []])
> [(3,8),(3,4)]
Your example:
fatherChild (Node 10 [Node 8 [Node 3 [], Node 5 []], Node 2 [Node 2 [], Node 0 []]])
> [(10,8),(10,2),(8,3),(8,5),(2,2),(2,0)]
Now, this doesn't answer your question about binary trees, but I would like to leave that to you as an exercise, because it will be very similar (except if you get stuck). (And please don't use rose trees as binary trees, because there is no type safety to ensure that there are always two children.)

A simple way to do it is by getting the value with an auxiliary function and then do the recursion:
data Tree a = Leaf a
| Node a (Tree a) (Tree a) deriving (Eq, Show)
exTree :: Tree Int
exTree = Node 10 t1 t2
t1 = Node 8 (Leaf 3) (Leaf 5)
t2 = Node 2 (Leaf 2) (Leaf 0)
relationshipBinaryTree :: Tree a -> [(a,a)]
relationshipBinaryTree (Leaf _) = []
relationshipBinaryTree (Node v i d) = [(v, getVal i), (v, getVal d)] ++ relationshipBinaryTree i ++ relationshipBinaryTree d
getVal (Node v _ _) = v
getVal (Leaf v) = v
relationshipBinaryTree exTree
=> [(10,8),(10,2),(8,3),(8,5),(2,2),(2,0)]

Related

Sumation of tree

So for this problem I tried to take the sum of all leaves in a tree. But it's shooting an error every time. I am providing a snippet of the code I wrote.
Sample case
t1 =NODE 1 (NODE 2 (NODE 3 (LEAF 4) (LEAF 5)) (LEAF 6)) (NODE 7 (LEAF 8) (LEAF 9))
Answer should be 32.
data Tree a = LEAF a | NODE a (Tree a) (Tree a) deriving (Show, Read, Eq)
tre (LEAF a) = a
tre (NODE a (Tree b) (Tree c)) = [Tree b, Tree c]
sum [] accum = []
sum list#(x:xs) accum = if tre x == Int
then sumTree xs (accum + x)
else sumTree x accum
sumTree :: Num p => Tree p -> p
sumTree p accum= let
list = tre p
in sum list accum
32
The Haskell snipet provided is not the idiomatic Haskell way of solving the problem.
You don't need the tre function => use Pattern matching on constructors of your type
You don't have to use tre x == Int let out the magic of type inference
I've provided the following snippet of the code, load it into ghci and use :i Tree and :i sumTree to understand the types
module Main where
data Tree a = Leaf a | Node a (Tree a) (Tree a) deriving (Show)
sumTree (Leaf a) = a
sumTree (Node a l r) = a + sumTree l + sumTree r
main = do
let tree = Node 5 (Node 21 (Leaf 14) (Leaf 13)) (Leaf 29)
putStrLn $ show tree
putStrLn $ show $ sumTree tree

How to fix the errors about return subtrees from the depth given in parameter

I want to return the list of all the subtrees of the initial tree with the depth given in parameter
I've tried to return the list of the tree when the depth is 0 and when depth matching with n, I want to decrement n and apply the map function using my function and the n parameter decremented to the list of subtrees
data Tree t = Node t [Tree t] deriving (Show, Eq)
exTree :: Tree Int
exTree = Node 1 [ Node 2 [], Node 3 [ Node 4 [], Node 5 [],Node 6 []]]
height :: Tree t -> Int
height (Node _ []) = 1
height (Node _ l) = 1 + maximum (map height l)
treemap :: (t->t) -> Tree t -> Tree t
treemap f (Node x []) = Node (f x) []
treemap f (Node x l) = Node (f x) (map (treemap f) l)
-- Here is the function concerned:
extrForest :: Int -> Tree t -> [Tree t]
extrForest 0 a = [a]
extrForest n (Node _ l) = map (extrForest (n-1)) l
Here is the error message:
Couldn't match type ‘[Tree t]’ with ‘Tree t’
Expected type: Tree t -> Tree t
Actual type: Tree t -> [Tree t]
Relevant bindings include
l :: [Tree t] (bound at ds2.hs:16:22)
extrForest :: Int -> Tree t -> [Tree t] (bound at ds2.hs:15:1)
In the first argument of ‘map’, namely ‘(extrForest (n - 1))’
In the expression: map (extrForest (n - 1)) l
Still don't quite understand what you need, so here is a very ad-hoc solution.
Looking at your error, it is clear that you have the common problem [a] vs [[a]].
When you look at the type signature map :: (a -> b) -> [a] -> [b] you see that your function has to take an [a] and return a simple [b], not [[b]], as this then needs to be mapped over again. However, your extForest returns a list of forests, so what you should do, is to concatenate them: concat . map. Turns out this is a common thing, and there's a Prelude function to do this: concatMap :: Foldable t => (a -> [b]) -> t a -> [b].

Can this implementation of in-order traversal of a binary tree be improved?

I wrote a straightforward in-order-traversal function (toList1) for a binary tree. However, I worry about its complexity (memory / time). Is there a better way to implement it?
data Tree a = Empty | Node a (Tree a) (Tree a)
toList1 :: (Tree a) -> [a]
toList1 Empty = []
toList1 (Node x lx rx) = (toList lx) ++ [x] ++ (toList rx)
Haskell's append ++ performs linearly in the length of its left argument, which means that you may get quadratic performance if the tree leans left.
One possibility would be to use difference list.
Another one would be to define a Foldable instance:
data Tree a = Empty | Node a (Tree a) (Tree a)
instance Foldable Tree where
foldr f z Empty = z
foldr f z (Node a l r) = foldr f (f a (foldr f z r)) l
then, in-order-traversal comes out naturally:
toList :: Tree a -> [a]
toList = foldr (:) []
and
\> let tr = Node "root" (Node "left" Empty Empty) (Node "right" Empty Empty)
\> toList tr
["left","root","right"]

Haskell Tree to List - preorder traversal

Given the following tree structure in Haskell:
data Tree = Leaf Int | Node Int Tree Tree deriving Show
How can I get Haskell to return a list of the data in pre-order?
e.g. given a tree:
Node 1 (Leaf 2) (Leaf 3)
return something like:
preorder = [1,2,3]
You could aim to a more general solution and make your data type an instance of Foldable.
There is a very similar example at hackage, but that implements a post-order visit.
If you want to support pre-order visits you will have to write something like this:
import qualified Data.Foldable as F
data Tree a = Leaf a | Node a (Tree a) (Tree a) deriving Show
instance F.Foldable Tree where
foldr f z (Leaf x) = f x z
foldr f z (Node k l r) = f k (F.foldr f (F.foldr f z r) l)
With this, you'll be able to use every function that works on Foldable types, like elem, foldr, foldr, sum, minimum, maximum and such (see here for reference).
In particular, the list you are searching for can be obtain with toList. Here are some examples of what you could write by having that instance declaration:
*Main> let t = Node 1 (Node 2 (Leaf 3) (Leaf 4)) (Leaf 5)
*Main> F.toList t
[1,2,3,4,5]
*Main> F.foldl (\a x -> a ++ [x]) [] t
[1,2,3,4,5]
*Main> F.foldr (\x a -> a ++ [x]) [] t
[5,4,3,2,1]
*Main> F.sum t
15
*Main> F.elem 3 t
True
*Main> F.elem 12 t
False
Use pattern matching
preorder (Leaf n) = [n]
preorder (Node n a b) = n:(preorder a) ++ (preorder b)
Ok, sorry about the late reply, but I got this working as follows:
preorder(Leaf n) = [n]
preorder(Node n treeL treeR) = [n] ++ preorder treeL ++ preorder treeR'code'
This however does not work for me still
preorder (Leaf n) = [n]
preorder (Node n a b) = n:(preorder a) ++ (preorder b)

How to represent tree with sharing in Haskell

I would like to represent a "tree" of the following shape in Haskell:
/\
/\/\
/\/\/\
/\/\/\/\
` ` ` ` `
/ and \ are the branches and ` the leaves. You can see that starting at any node, following the left path, then the right gets you to the same node as following the right path then the left. You should be able to label the leaves, apply a function of the two decendants at each node, and propagate this information to the root in O(n^2) time. My naive efforts are giving me an exponential run time. Any hints?
It is certainly possible to construct a tree with shared nodes. For example, we could just define:
data Tree a = Leaf a | Node (Tree a) (Tree a)
and then carefully construct a value of this type as in
tree :: Tree Int
tree = Node t1 t2
where
t1 = Node t3 t4
t2 = Node t4 t5
t3 = Leaf 2
t4 = Leaf 3
t5 = Leaf 5
to achieve sharing of subtrees (in this case t4).
However, as this form of sharing is not observable in Haskell, it is very hard to maintain: for example if you traverse a tree to relabel its leaves
relabel :: (a -> b) -> Tree a -> Tree b
relabel f (Leaf x) = Leaf (f x)
relabel f (Node l r) = Node (relabel f l) (relabel f r)
you loose sharing. Also, when doing a bottom-up computation such as
sum :: Num a => Tree a -> a
sum (Leaf n) = n
sum (Node l r) = sum l + sum r
you end up not taking advantage of sharing and possibly duplicate work.
To overcome these problems, you can make sharing explicit (and hence observable) by encoding your trees in a graph-like manner:
type Ptr = Int
data Tree' a = Leaf a | Node Ptr Ptr
data Tree a = Tree {root :: Ptr, env :: Map Ptr (Tree' a)}
The tree from the example above can now be written as
tree :: Tree Int
tree = Tree {root = 0, env = fromList ts}
where
ts = [(0, Node 1 2), (1, Node 3 4), (2, Node 4 5),
(3, Leaf 2), (4, Leaf 3), (5, Leaf 5)]
The price to pay is that functions that traverse these structures are somewhat cumbersome to write, but we can now define for example a relabeling function that preserves sharing
relabel :: (a -> b) -> Tree a -> Tree b
relabel f (Tree root env) = Tree root (fmap g env)
where
g (Leaf x) = Leaf (f x)
g (Node l r) = Node l r
and a sum function that doesn't duplicate work when the tree has shared nodes:
sum :: Num a => Tree a -> a
sum (Tree root env) = fromJust (lookup root env')
where
env' = fmap f env
f (Leaf n) = n
f (Node l r) = fromJust (lookup l env') + fromJust (lookup r env')
Perhaps you can represent it simply as a list of leaves and apply the function level by level until you're down to one value, i.e. something like this:
type Tree a = [a]
propagate :: (a -> a -> a) -> Tree a -> a
propagate f xs =
case zipWith f xs (tail xs) of
[x] -> x
xs' -> propagate f xs'

Resources