With this function, i can remove the minimum in a binary search tree:
data BTree a = Empty
| Node a (BTree a) (BTree a)
semmin :: BTree a -> BTree a
semmin (Node x Empty Empty) = Empty
semmin (Node x l r) = Node x (semmin l) r
I want to retrieve the minimum value and the tree without this minimum, the trick is, i can traverse it only once.
The type is mimSmim :: BTree a -> (a,BTree a)
how should i do it?
EDIT:
Does this count as one traverse?
semmin :: BTree a -> (a,BTree a)
semmin (Node x Empty Empty) = (x,Empty)
semmin (Node x l r) = let i= (semmin l)
in (fst(i),(Node x (snd(i)) r))
Here's a hint: If you are at a Node x l r and you already knew that the left tree's mimSmim l was (a, l'), then the Node's mimSmim (Node x l r) would be (a, Node x l' r).
You are looking for a zipper. A [zipper][1] is a representation of another data structure that lets you focus one section of the entire structure without losing the rest. Please see the last chapter of Learn You A Haskell for an intuitive approach to developing the zipper data type and functions to use on it.
The posted code is on the right track, even if not completely correct:
semmin :: BTree a -> (a,BTree a)
semmin (Node x Empty Empty) = (x,Empty)
semmin (Node x l r) = let i= (semmin l)
in (fst(i),(Node x (snd(i)) r))
As a hint for improving your code, not that the following crashes:
semmin (Node 1 Empty (Node 2 Empty Empty))
Also, to improve readability a bit, I would suggest:
semmin :: BTree a -> (a,BTree a)
semmin (Node x Empty Empty) = (x,Empty)
semmin (Node x l r) = let (minValue, minTree) = semmin l
in (minValue, Node x minTree r)
Finally, this looks as if it's returning the whole tree back, instead of the tree at which the minimum is found. Check if that's the case, and if that's what you want.
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>
Given a tree that looks like this:
data Tree a = Leaf | Node (Tree a) a (Tree a)
And a fold function that looks like this:
foldTree :: (b -> a -> b -> b) -> b -> Tree a -> b
foldTree _ b Leaf = b
foldTree fn b (Node lt x rt) = f (foldTree fn b lt) x (foldTree fn b rt)
I want to be able to write a takeWhileTree function that looks like this:
treeTakeWhile :: (a -> Bool) -> Tree a -> Tree a
I want it to mimic the 'normal' list takeWhile function so that it returns the largest possible tree whose elements satisfy the given condition.
So, if a tree t = Node (Node Leaf 10 Leaf) 4 (Node Leaf 5 Leaf), then:
treeTakeWhile (> 5) T = Leaf
treeTakeWhile (>= 4) T = T
treeTakeWhile (< 5) T = Node Leaf 4 Leaf
treeTakeWHile (< 8) T = Node Leaf 4 (Node Leaf 5 Leaf)
So far I seem to not be able to formulate what to pass into foldTree.
In the definition of foldtree, the function can be broken down as: b probably being the left subtree, a probably being the value in the current node and b probably being the right subtree.
Therefore, the function passed to treeTakeWhile has to be applied to all these parts of the node in some manner while being able to stop when the operation no longer applies.
treeTakeWhile fn = foldTree (\xs x ys -> if y then g else Leaf) Node()
where g = (lt, x, rt)
y = fn (Node lt x rt)
The above is clearly wrong but I am not sure how to express the act of applying the function to the current node's value followed by the left tree and the right tree here. Could somebody point me in the right direction? And how will the fold be able to produce the required tree?
Edit 1:
Okay, based on your feedback, I have gotten to a place where I think I am pretty close to the answer but cannot figure out why the compiler still complains:
treeTakeWhile :: (a -> Bool) -> Tree a -> Tree a
treeTakeWhile c = foldTree f acc
where acc = Leaf
f l x r = if c x then Node (f lt) x (f rt) else Leaf
As far as I can tell, foldTree is being passed the right arguments now. And the predicate is also being evaluated as required at each level of the tree. The return value is always of type Tree as well.
Instead of using foldTree immediately, let's first aim to define the function itself.
Basically there are three options here:
the tree is a Leaf, regardless what the condition is, the result is a Leaf as well;
the tree is a Node and the condition is satsified, then we yield the element, and recurse on the subtrees;
the tree is a Node and the condition is not satisfied, then the result is a Leaf.
We can encode these rules as:
treeTakeWhile :: (a -> Bool) -> Tree a -> Tree a
treeTakeWhile c = go
where go Leaf = Leaf -- (1)
go (Node l x r) | c x = Node (go l) x (go r) -- (2)
| otherwise = Leaf -- (3)
this then yields the expected results:
Prelude> treeTakeWhile (>5) t
Leaf
Prelude> treeTakeWhile (>=4) t
Node (Node Leaf 10 Leaf) 4 (Node Leaf 5 Leaf)
Prelude> treeTakeWhile (<5) t
Node Leaf 4 Leaf
Prelude> treeTakeWhile (<8) t
Node Leaf 4 (Node Leaf 5 Leaf)
Moving this to a foldTree
Now we aim to move the logic to a foldTree, we can thus write the function as:
treeTakeWhile :: (a -> Bool) -> Tree a -> Tree a
treeTakeWhile c = foldTree f x0
where f tl x tr = -- ...
x0 = -- ...
The x0 is the value we should fill in for Leafs, but we already know what that is: it is the first rule (1) and we should thus return a Leaf as well.
For f we need a function Tree a -> a -> Tree a -> Tree a. The first operand tl is the treeTakeWhile of the left subtree (this would be equivalent to go l in the original function implementation), the second parameter x is the value encoded in the Node, and the last parameter tr is the result of treeTakeWhile on the second subtree (so equivalent to go r), so:
treeTakeWhile :: (a -> Bool) -> Tree a -> Tree a
treeTakeWhile c = foldTree f x0
where f tl x tr = -- ...
x0 = -- ...
(leave this as an exercise).
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)
I am learning Haskell using The Haskell School of Expression: Learning Functional Programming through Multimedia and I am unsure how to go about solving this exercise.
Using the definition of trees given by
data Tree a = Node (Tree a) (Tree a) | Leaf a
Define tree versions of the list functions zip and zipWith. There
will be cases at the leaves or where trees are of different shapes
where you’ll have to make design decisions. Try to make your decisions
as elegant as possible.
For zip I have this but I am unsure if it is "elegant"
zipTree :: Tree a -> Tree b -> Tree (a,b)
zipTree (Leaf a) (Leaf b) = Leaf (a,b)
zipTree (Node l1 r1) (Node l2 r2) =
let l = zipTree l1 l2
r = zipTree r1 r2
in Node l r
-- Problems...
zipTree (Node _ _) (Leaf _) = Node undefined undefined
zipTree (Leaf _) (Node _ _) = Node undefined undefined
And I am unsure how to adapt it to have zipWith functionality although I do know a elegant definition of zipWith.
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys
zipWith _ _ _ = []
First of all I believe your solution is not elegant because you are using undefined.
You want to avoid partial functions, and structures, as much as possible and simply inserting some Node undefined undefined in a tree structure doesn't sound like a good idea.
Think about this: once you have a Node undefined undefined how would it act with the other operations on the tree? You'd probably get tons of exceptions.
So you have to find an alternative.
zipTree (Node l r) (Leaf a) = Node x y
where
x = ... ?
y = ... ?
Now how should x and y be defined? x should depend on l and Leaf a while y should depend on r and Leaf a.
The easiest way to define this case is to simply perform the recursive calls:
zipTree (Node l r) a#(Leaf _) = Node (zipTree l a) (zipTree r a)
So we are zipping all leafs in the l and r subtrees with the leaf a.
As for the zipWithTree: that's easy. You have to add an f parameter and use f x y instead of (x, y) when you perform the zipping, which is done only in the Leaf v Leaf case:
zipWithTree f (Leaf a) (Leaf b) = Leaf $ f a b
Obviously you have to add the f parameter to all the rules and pass f to recursive calls.
Note that there is also an other way to define zipWith, which is:
zipTree (Node _ _) (Leaf a) = Leaf (undefined, a)
This still isn't a good solution because it introduces an undefined however it has some advantages against the Node undefined undefined solution:
It acts for similarly to zip from lists. zip [1,2] [1,2,3,4] == [(1,1), (2,2)] so you stop when the shorter list ends.
The undefined is inside the value. This allows for example to have:
mapTree snd (zipTree x y) == y
whenever x has longer branches. Using Node undefined undefined you have mapTree f (zipTree x y) is always an exception whenever the trees aren't isomorphic (because mapTree will try to evaluate undefined).
I am learning Haskell using The Haskell School of Expression: Learning Functional Programming through Multimedia and I am unsure how to go about solving this exercise.
Using the definition of trees given by
data Tree a = Node (Tree a) (Tree a) | Leaf a
Define tree versions of the list functions zip and zipWith. There
will be cases at the leaves or where trees are of different shapes
where you’ll have to make design decisions. Try to make your decisions
as elegant as possible.
For zip I have this but I am unsure if it is "elegant"
zipTree :: Tree a -> Tree b -> Tree (a,b)
zipTree (Leaf a) (Leaf b) = Leaf (a,b)
zipTree (Node l1 r1) (Node l2 r2) =
let l = zipTree l1 l2
r = zipTree r1 r2
in Node l r
-- Problems...
zipTree (Node _ _) (Leaf _) = Node undefined undefined
zipTree (Leaf _) (Node _ _) = Node undefined undefined
And I am unsure how to adapt it to have zipWith functionality although I do know a elegant definition of zipWith.
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys
zipWith _ _ _ = []
First of all I believe your solution is not elegant because you are using undefined.
You want to avoid partial functions, and structures, as much as possible and simply inserting some Node undefined undefined in a tree structure doesn't sound like a good idea.
Think about this: once you have a Node undefined undefined how would it act with the other operations on the tree? You'd probably get tons of exceptions.
So you have to find an alternative.
zipTree (Node l r) (Leaf a) = Node x y
where
x = ... ?
y = ... ?
Now how should x and y be defined? x should depend on l and Leaf a while y should depend on r and Leaf a.
The easiest way to define this case is to simply perform the recursive calls:
zipTree (Node l r) a#(Leaf _) = Node (zipTree l a) (zipTree r a)
So we are zipping all leafs in the l and r subtrees with the leaf a.
As for the zipWithTree: that's easy. You have to add an f parameter and use f x y instead of (x, y) when you perform the zipping, which is done only in the Leaf v Leaf case:
zipWithTree f (Leaf a) (Leaf b) = Leaf $ f a b
Obviously you have to add the f parameter to all the rules and pass f to recursive calls.
Note that there is also an other way to define zipWith, which is:
zipTree (Node _ _) (Leaf a) = Leaf (undefined, a)
This still isn't a good solution because it introduces an undefined however it has some advantages against the Node undefined undefined solution:
It acts for similarly to zip from lists. zip [1,2] [1,2,3,4] == [(1,1), (2,2)] so you stop when the shorter list ends.
The undefined is inside the value. This allows for example to have:
mapTree snd (zipTree x y) == y
whenever x has longer branches. Using Node undefined undefined you have mapTree f (zipTree x y) is always an exception whenever the trees aren't isomorphic (because mapTree will try to evaluate undefined).