Function to calculate portions and instance of a class in haskell

110 Views Asked by At

in preparation for an exam on haskell our teacher gave us some exercises but was then sick on the day we were supposed to discuss them. Some of them I solved, some of them I can't figure out:

1) Write a function that calculates the parts of vodka and energy in a longdrink:

data VodkaEnergy = Vodka Int | Energy Int | Mix VodkaEnergy VodkaEnergy

I didn't manage to do much more than:

mixPortion :: VodkaEnergy->(Int,Int)
mixPortion (Vodka x) = (x,0)
mixPortion (Energy y) = (0,y)
mixPortion (Mix x y) = (a,b)
 where a = fst (mixPortion x)
       b = snd (mixPortion y)

I realize this is a oversimplified solution that doesn't catch all inputs but I'm at a loss.

1b) VodkaEnergy should be a part of Eq, making 2 longdrinks equal if they have the same ratio of vodka and energy.

This one I can't solve until I have the function but I'm assuming it would go like this:

instance Eq VodkaEnergy where
 x == y    = mixPortion x == mixPortion y

typeclasses are still difficult for me, so do correct me.

2) Write a function that counts the paths that has an even amount of Leaves + Nodes in

data Tree = Leaf Int | Ndoe Int Tree Tree

Again, at a loss all I got so far is a function that counts all nodes and leaves in the tree, which doesn't help much

3)

data Eq a => Set a = S [a]

Make set an instance of Eq, where two sets are the same if all elements of set1 are contained in set2 and vice versa.

This one confuses me because the data type in the task doesn't compile with the "Eq a =>" there. But what I tried so far is this:

instance (Eq a) => Eq (Set a) where
 x:set1 == set2      = x `elem` set2 && set1 == set2 && set2 == set1

but the "x:set1" part doesn't compile because it expects a different type

I know these are probably newbie questions. I mean, I AM a newbie to haskell. I'm finding it hard to find good ressources for questions on haskell like these, so do link me if I missed the answers floating on the web somewhere. I'm honestly a little desperate, the exam is coming closer and I still don't quite 'get' functional programming. Thank you very much for any help.

1

There are 1 best solutions below

1
On BEST ANSWER
  1. a) Almost good, but you have to add up the vodka and energy components of both parts of the mix, not just the vodka from the first and the energy from the second. Furthermore it is often nicer to use pattern-matching instead of accessor methods like fst and snd if possible.

    mixPortion :: VodkaEnergy -> (Int,Int)
    mixPortion (Vodka x)  = (x,0)
    mixPortion (Energy y) = (0,y)
    mixPortion (Mix x y)  = (v1+v2,e1+e2)
      where (v1,e1) = (mixPortion x)
            (v2,e2) = (mixPortion y)
    

    b) is correct.

  2. As I said in the comment I don't really know what exactly question wants. Assuming that the task is to find the number of even paths from the root to any leaf, you could approach it like this: You write a function evenOddBranches :: Tree -> (Int,Int) that gives the number of even paths and odd paths. This is easier, since an even path of a subtree of a node is an odd path if you add that node to the path. That way you get a simple recursion: The number even paths of a node are the sum of the odd paths of it's two subtrees and the number odd paths is the sum of the even paths of the subtrees.

  3. The Eq constraint on Set used to be correct syntax but isn't anymore since Haskell 2010. The correct way to do this is to just leaf out the Eq constraint in the data definition and add it where needed.

    There are also some flaws with your code. First of all you can not pattern-match on it with x:set1, because it is not a list, but a Set, which means you have the S wrapper. So instead you have to pattern-match like this: S (x:xs). Note that xs is a list and not a Set, so for the recursive call you have to wrap it with S again. Furthermore if you match on S (x:xs) you should also match on S []. So fixing your code on a syntactical level we get the following:

    data Set a = S [a]
    instance (Eq a) => Eq (Set a) where
      S [] == S []     = True
      S [] == S (_:_)  = False
      S (x:xs) == S ys = x `elem` ys && S xs == S ys && S ys == S xs
    

    This will compile but does not work. For example with S [0] == S [0] is False.

    The easiest way to write a set equality is with two set inclusions. So you should write a function subsetEq :: Eq a => Set a -> Set a -> Bool that is True iff every element of the first set is also an element of the second set. Then you can implement set equality like this:

    instance (Eq a) => Eq (Set a) where
      set1 == set2 = set1 `subsetEq` set2 && set2 `subsetEq` set1
    

    I think with only an Eq constraint this is actually the best you can do.