0
votes

I have a List [(String, [(String, Float)] and want to calculate the average of the floats, so that I get as result [(String, Float)]. You'll understand reading the code.

type StudentName = String
type CourseName  = String
type ExamScore   = (CourseName, Float)
type StudentData = [(StudentName, [ExamScore])]

--Delete duplicated entries
filterDuplicates :: StudentData -> StudentData
filterDuplicates [] = []
filterDuplicates sd = [(head sd)] ++ filterDuplicates(filter (\ x -> x /= (head sd)) (tail sd))

--Delete entries whose score is not in scope or whose are not listed the list of course names
filterValidEntries :: [ExamScore] -> [CourseName] -> [ExamScore]
filterValidEntries es cn = filter (\ x -> ((fst x) `elem` cn) && ((snd x) >= 1.0 && (snd x) <= 5.0)) es

--Calulate the average of the cleared data
calculateAverages :: StudentData -> [CourseName] -> [(StudentName, Float)]
calculateAverages sd cn = map createTupel (filterDuplicates sd)
    where createTupel x = ((fst x), ((foldr (+) 0 (snd(filterValidEntries(snd x) cn))) / fromIntegral(length (filterValidEntries(snd x) cn))))

Trying to compile this, I am getting the following error:

    * Couldn't match expected type `(a0, t0 b)'
                  with actual type `[ExamScore]'
    * In the first argument of `snd', namely
        `(filterValidEntries (snd x) cn)'
      In the third argument of `foldr', namely
        `(snd (filterValidEntries (snd x) cn))'
      In the first argument of `(/)', namely
        `(foldr (+) 0 (snd (filterValidEntries (snd x) cn)))'
    * Relevant bindings include
        createTupel :: (a, [ExamScore]) -> (a, b)
          (bound at C:\\Users\Lennart\sciebo\Semster 1\Info\Übungen\Übung 06\WI0
4_B06_A04_G01.hs:72:15)
   |
72 |         where createTupel x = ((fst x), ((foldr (+) 0 (snd(filterValidEntri
es(snd x) cn))) / fromIntegral(length (filterValidEntries(snd x) cn))))
   |                                                            ^^^^^^^^^^^^^^^^
^^^^^^^^^^^^

I hope you can help me, thank you.

1
Hint: a 2-tuple is not the same as a list of 2-tuples.Willem Van Onsem
Where is the data coming from in the first place that you need to remove duplicates? Are you building that list? You might want to use Data.Map to make it easier to update without adding duplicates to the collection in the first place.chepner
I dont get it. filterValidEntries does require a list of ExamScores and the second argurment is such a list... Where is the problem? @Willem It is my homework chepner. How do you mean I can use map?longroad

1 Answers

3
votes

A minor, but important, comment on style. Haskell function application is never written f(x+y) without space between the f and (. It's always written f (x+y).

Anyway, here's how to figure out this error message. The important bits are that GHC expected a type of the form (a, t b) -- the a, t, and b are less important than the fact that it expected a tuple (i.e., pair) type, but it was given an [ExamScore], which is clearly a list and not the tuple it expected.

Where did this happen? Well, as the error message says, the problem occurred in trying to pass the first argument to snd -- namely (filterValidEntries (snd x) cn).

Note that snd, since it grabs the second element of a tuple, obviously expected a tuple. Yet, the argument filterValidEntries (snd x) cn does not return a tuple, it actually returns a list [ExamScore].

That's your problem. Did you really intend to pass the argument filterValidEntries (snd x) cn, which returns a list, to the function snd, which expects a tuple? No, you did not. What were you trying to do? Maybe map snd to each element of the list?