Write a function that counts the number of elements in a rosetree - haskell

Write a function
that counts the number of elements in a rosetree.
I tried counts the number of elements in a rosetree.
data RoseTree a = RoseNode a [RoseTree a]
deriving Show
things :: RoseTree String
things =
RoseNode "thing" [
RoseNode "animal" [
RoseNode "cat" [], RoseNode "dog" []
],
RoseNode "metal" [
RoseNode "alloy" [
RoseNode "steel" [], RoseNode "bronze" []
],
RoseNode "element" [
RoseNode "gold" [], RoseNode "tin" [], RoseNode "iron" []
]
],
RoseNode "fruit" [
RoseNode "apple" [
RoseNode "Granny Smith" [], RoseNode "Pink Lady" []
],
RoseNode "banana" [],
RoseNode "orange" []
],
RoseNode "astronomical object" [
RoseNode "Planet" [
RoseNode "Earth" [], RoseNode "Mars" []
],
RoseNode "Star" [
RoseNode "The Sun" [], RoseNode "Sirius" []
],
RoseNode "Galaxy" [
RoseNode "Milky Way" []
]
]
]
It should be 27, however, it returns 4.
EDIT: Here is my attempt:
roseSize x = case x of
RoseNode a [] -> 0
RoseNode a (x:xs) -> 1 + roseSize (RoseNode a xs)

It should be 27, however, it returns 4.
roseSize x = case x of
RoseNode a [] -> 0
RoseNode a (x:xs) -> 1 + roseSize (RoseNode a xs)
So you're not counting the sub-trees recursively. Try instead (fixed: base case to 1),
roseSize (RoseNode _ []) = 1
roseSize (RoseNode a (t:ts)) = roseSize t + roseSize (RoseNode a ts)
The missing part is roseSize t.
Otherwise you're only making recursive calls for the first layer of the tree.
If you evaluate your function by hand this becomes apparent,
roseSize things
~> roseSize (RoseNode "thing" [ animals, metals, fruits, astronomical_objects ]
~> 1 + roseSize (RoseNode "thing" [ metals, fruits, astronomical_objects ])
~> 1 + 1 + roseSize (RoseNode "thing" [ fruits, astronomical_objects ])
~> 1 + 1 + 1 + roseSize (RoseNode "thing" [ astronomical_objects ])
~> 1 + 1 + 1 + 1 + roseSize (RoseNode "thing" [])
~> 1 + 1 + 1 + 1 + 0
whereas with roseSize t in the function body the evaluation becomes
roseSize things
~> roseSize (RoseNode "thing" [ animals, metals, fruits, astronomical_objects ]
~> roseSize animals
+ roseSize (RoseNode "thing" [ metals, fruits, astronomical_objects ])
~> roseSize (RoseNode "animal" [ cat, dog ])
+ roseSize (RoseNode "thing" [ metals, fruits, astronomical_objects ])
~> roseSize cat
+ roseSize (RoseNode "animal" [ dog ])
+ roseSize (RoseNode "thing" [ metals, fruits, astronomical_objects ])
~> 1 -- given the base case of 1 instead of 0
+ roseSize (RoseNode "animal" [ dog ])
+ roseSize (RoseNode "thing" [ metals, fruits, astronomical_objects ])
~> ...
As an exercise, making this function explicitly recursive is fine.
But you may want to consider a more general approach, either using higher-order functions like PF. Castro does it, or an existing data structure like Data.Tree of containers:
import qualified Data.Tree as T
import Data.Tree (Tree(..))
things :: Tree String
things = Node "thing" [ animals, metals, fruits, astronomical_objects ]
where
animals = Node "animal" (map pure [ "cat", "dog" ])
metals = Node "metal" [ alloys, elements ]
alloys = Node "alloy" (map pure [ "steel", "bronze" ])
elements = Node "element" (map pure [ "gold", "tin", "iron" ])
fruits = ...
astronomical_objects = ...
Since a Data.Tree is Foldable, you can use length on it.
So it's not necessary to define a custom roseSize function.
At this point you're counting the nodes in a tree, and not the leaves of a tree, with leaves being the actual objects rather than the categories to which they belong. So you may actually be interested in counting the leaves.
You could do that by creating a function that finds the leaves:
leaves :: Tree a -> [a]
leaves (Node x []) = ... -- x is a leaf
leaves (Node _x ts) = ... -- _x isn't a leaf
With this template you can't easily use explicit recursion, i.e. matching on Node x (t:ts) and calling leaves on ts, since then the non-leaf case eventually ends in the base case, making the exhausted category appear as a leaf. But you can use higher-order functions to abstract out the recursion, e.g. concat, map, or concatMap of Prelude.
Using a library rose tree gives you other advantages, too, for example a bunch of other type class instances (Applicative giving you pure "foo" to construct a singleton tree / leaf) and a pretty-printing function:
> putStrLn $ T.drawTree things
thing
|
+- animal
| |
| +- cat
| |
| `- dog
|
`- metal
|
+- alloy
| |
| +- steel
| |
| `- bronze
|
...

You should use map and fold with RoseTrees, e.g.:
size (RoseNode x xs) = 1 + (sum (map size xs))
where sum is just:
sum = foldl (+) 0

Related

List Comprehension with list of lists

I have problems to understand the following piece of code:
treePositions :: Tree a -> [[Int]]
treePositions (Node _ ts) =
[] : [ (i : is ) | i <- [0..(length ts - 1)],
is <- treePositions (index ts i) ]
This function would calculate any valid paths to a position in the given tree, where for every node the edges are marked with 0..lastOutgoingEdge.
If I understood it right the index function would return the node at Index i in the node list of the tree.
index :: [a] -> Int -> a
index :: [a] -> Int -> a
index [] i = error "invalid index"
index (x:xs) 0 = x
index (x:xs) i = ith xs (i-1)
Now for given trees:
t1 = Node "a" [
Node "b" [
Node "c"[],
Node "d"[]
]
]
t2 = Node "z" []
the function would return:
treePositions t1 == [ [], [0], [0,0], [0,1] ]
treePositions t2 == [ [] ]
What I don't understand is this part:
[] : [ (i : is ) | i <- [0..(length ts - 1)],is <- treePositions (index ts i) ]
My thoughts:
If I have x|x <- [0..10], x < 2. This would translate in "take every x in [0..10] for which x < 2 applies. So if I would take every i in [0..(length ts - 1)], how would this then return lists for a condition?
In your case, the part after the comma is not a condition, but a second generator. Simplified, the notation looks like this:
> [ (a, b) | a <- [1..3], b <- [1..2] ]
> [(1,1),(1,2),(2,1),(2,2),(3,1),(3,2)]
The example compherension above means the following:
go through list [1..3], and for every element of it,
go through list [1..2], and for every element of it,
produce a tuple
Further, a generator can depend on elements of previous generators, e.g.:
> [ (a, b) | a <- [1..3], b <- [1..a] ]
> [(1,1),(2,1),(2,2),(3,1),(3,2),(3,3)]
So in your case:
[ (i : is ) | i <- [0..(length ts - 1)],is <- treePositions (index ts i) ]
the logic is this:
for every i in 0..(length ts - 1),
go through every is in treePositions (index ts i),
and produce i : is as result

What does pipe symbol mean?

The following is the haskell comprehensions, what I don't understand is the pipe symbol. What does it mean and what is its role in the function?
boomBangs xs = [ if x < 10 then "BOOM!" else "BANG!" | x <- xs, odd x]
ghci> let xxs = [[1,3,5,2,3,1,2,4,5],[1,2,3,4,5,6,7,8,9],[1,2,4,2,1,6,3,1,3,2,3,6]]
ghci> [ [ x | x <- xs, even x ] | xs <- xxs]
[[2,2,4],[2,4,6,8],[2,4,2,6,2,6]]
Its expression/syntax for list comprehensions. An easy example is the following,
import Data.Char (toUpper)
[toUpper c | c <- s]
You pass a string (list of chars), [ s ], "Hello", to the generator [ c <- s ] , this feeds each character of s to the left-hand expression [ toUpper c ], building a new list. The result of this list comprehension would be "HELLO".

Binary Tree type constructor in Haskell

I'm trying binary tree type constructor which is:
data Tree a = Leaf a | Branch a (Tree a) (Tree a)
How we prove that not all kinds of binary tree can be represented by this constructor? How we improve this definition to cover all types of binary tree? And how it works?
Your Tree a has labels of type a at every Branch and every Leaf constructor. So, for example, Branch 'u' (Branch 'n' (Leaf 'i') (Leaf 'p')) (Leaf 'z') looks like this:
+-'u'-+
| |
+-'n'-+ 'z'
| |
'i' 'p'
That excludes, say, trees with different labels at the nodes and leaves, or trees that are labelled only internally or only externally. For example, this tree has numbers at the leaves and characters at the nodes.
+-'o'-+
| |
+-'h'-+ 9
| |
7 2
(You can use Tree (Either n l) but that doesn't encode the invariant that only ns appear internally and only ls appear externally.)
Since this appears to be a homework assignment I won't tell you what a more general type of tree might look like, but I'm sure you can figure it out.
Ask yourself, how many a values can your tree hold? They appear either in leaves or nodes,
data Tree a = Leaf a | Branch a (Tree a) (Tree a)
so
num_values = 1 | ( 1 + num_values + num_values )
It doesn't make much sense in this form, so let's write it as
numvals = 1 : [ 1 + s | s <- diagonalize
[ [ n + m | m <- numvals ]
| n <- numvals ] ]
diagonalize :: [[a]] -> [a]
diagonalize ((n:ns):t) = n:go [ns] t
where
go as (b:bs) = map head as ++ go (b:map tail as) bs
so that we get
~> take 100 numvals
[1,3,5,5,7,7,7,7,7,9,9,9,9,9,11,9,9,9,11,11,11,11,9,9,11,13,11,13,11,9,9,11,13,1
3,13,13,11,9,9,11,13,13,15,13,13,11,11,11,11,13,13,15,15,13,13,11,11,11,13,13,13
,15,15,15,13,13,13,11,11,13,15,13,15,15,15,15,13,15,13,11,11,13,15,15,15,15,15,1
5,15,15,15,13,11,11,13,15,15,17,15,15]
but you want 0, 2, 4, ... to appear there as well.
edit:
It is easy to fix this, with
data Tree a = Leaf | Branch a (Tree a) (Tree a)
Now
numvals2 = 0 : [ 1 + s | s <- diagonalize
[ [ n + m | m <- numvals2 ]
| n <- numvals2 ] ]
and
~> take 100 numvals2
[0,1,2,2,3,3,3,3,3,4,4,4,4,4,5,4,4,4,5,5,5,5,4,4,5,6,5,6,5,4,4,5,6,6,6,6,5,4,4,5
,6,6,7,6,6,5,5,5,5,6,6,7,7,6,6,5,5,5,6,6,6,7,7,7,6,6,6,5,5,6,7,6,7,7,7,7,6,7,6,5
,5,6,7,7,7,7,7,7,7,7,7,6,5,5,6,7,7,8,7,7]

Haskell dot dot notation on list - unexpected output

One of the questions that came up in one of my lectures was the following:
trips :: [(Int, Int, Int)]
trips = [ (x,y,z) | z <- [2..], y <- [2..z-1], x <- [2..y-1] ]
What is the first five elements output?
Now I thought I was aware how dot dot notation worked, but when I put the above into a compiler the output is:
(2, 3, 4), (2, 3, 5), (2, 4, 5), (3, 4, 5), (2, 3, 6) etc.
How does this happen?
I thought if things begun with [2..] then all the subsequent lists would begin with two? z is defined as [2..] yet it never once displays 2 as the third int. I'm obviously missing something here but I'm not entirely sure what.
[ (x,y,z) | z <- [2..], y <- [2..z-1], x <- [2..y-1] ] =
[ (x,y,2) | y <- [2..2-1], x <- [2..y-1] ] ++
[ (x,y,3) | y <- [2..3-1], x <- [2..y-1] ] ++
[ (x,y,4) | y <- [2..4-1], x <- [2..y-1] ] ++
... =
[ (x,y,2) | y <- [2..1], x <- [2..y-1] ] ++
[ (x,y,3) | y <- [2..2], x <- [2..y-1] ] ++
[ (x,y,4) | y <- [2..3], x <- [2..y-1] ] ++
... =
[ (x,y,2) | y <- [], x <- [2..y-1] ] ++
[ (x,y,3) | y <- [2], x <- [2..y-1] ] ++
[ (x,y,4) | y <- [2,3], x <- [2..y-1] ] ++
...
Note the range y <- [2..2-1] i.e. y <- [2..1] i.e. y <- []. Because of this, there are no triples (x,y,2) to generate.
Similarly, when y is 2, the range z <- [2..y-1] will generate nothing, and we do not get triples of the form (x,2,3).

Searching rose tree in Haskell

I'm trying to write a function searching for a given element in a rose tree and returning it's location.
It may be clearer when I show you what I already got:
Given a tree with a definition:
data Tree text = Node value
[Tree value]
for example:
test = Node "1" [
Node "11" [
Node "111" [],
Node "112" [
Node "1121" [], Node "1122" [], Node "1123" []
]
],
Node "12" []
]
1
11 12
111 112
1121 1122 1123
I'm looking for a function search:
search :: String -> Tree String -> [Integer]
search 1123 test -> should return [1,2,3]
- first subtree of 1=11 -> 2nd subtree of 11=112, 3rd subtree of 112=1123
I know how to iterate through tree,
display (Node v xs) = v ++ concatMap display xs
But have no idea how can I assign integer value to every element of subtrees array and additionally pass it recursively from upper to lower parts of the tree.
Can you guys direct me where/how to look for a solution? I'm very new to Haskell..
The easiest way is to let the function return the list of all paths to a node with the desired data (there should only ever be at most one in the tree, I suppose, but that doesn't matter) first, and then use the first of these:
searchList :: (Eq a) => a -> Tree a -> [[Integer]]
searchList val (Node dat subs)
| val == dat = [[]] -- empty path
| otherwise = concat [map (c:) (searchList val t) | (c,t) <- zip [1 .. ] subs]
search :: Eq a => a -> Tree a -> [Integer]
search val t = case searchList val t of
(p:_) -> p
_ -> error "Value not found"
If Daniel Wagner's suspicion is correct and your trees are tries, you can search more efficiently, but the principle remains the same, however, since we now know that we either have one node with the desired data or none, the result is more appropriately a Maybe [Integer]:
import Data.List (isPrefixOf)
import Control.Monad -- for the MonadPlus instance of Maybe
searchTrie :: String -> Tree String -> Maybe [Integer]
searchTrie target (Node val subs)
| val == target = Just []
| val `isPrefixOf` target = case dropWhile smaller (zip [1 .. ] subs) of
((c,t):_) -> fmap (c:) $ searchTrie target t
_ -> Nothing
| otherwise = Nothing
where
smaller (_,Node v _) = v < take (length v) target

Resources