Question

I have a function which calculates the ages of students in class:

averageMarks :: [(String, Int)] -> Int
averageMarks list = sum (map snd list) `div` length(list)

i.e. students = [("Amy", 6), ("Scott", 12)] = Would yield a value of 9.

Now I have a function which will return a bool whenever a value is found in within the list of students.

filterAverageMarks :: Int -> Class -> Bool
filterAverageMarks r (teacher, assistant, code, students)
        | elem r [averageMarks(students)]   = True
        | otherwise                         = False

This works perfectly fine, however, now I'm trying to search for a value of ranges; be it, "students with ages higher than 1".

The change in function is now:

filterAverageMarks :: Int -> Class -> Bool
filterAverageMarks r (teacher, assistant, code, students)
        | elem n [averageMarks(students)]   = True
        | otherwise                         = False
            where n >= r

This function is not correct, but I would like it to return True for all matches of 'n' when 'n' is bigger or equal to a value I give it. (for this example, '1').

Any help on correcting this syntax would be most appreciated! Thanks,

alex


EDIT:

Sorry I wasn't very clear, basically, I have a 'Class' type:

type Class = (Teacher, Assistant, Code, Students)
type Student = [(String, Int)]   ---- Name & Age

I want to write a function which takes an 'age' then displays the Teacher of the class with the average age of all the students. I have a list of loads of different 'classes' (called testClasses).

So to go about this I have writen the above function 'averageMarks' which will go though the students in each 'class' and work out the average.

The filterAverageMarks was supposed to return a 'True' for every time 'r' is matched (r = the supplied 'age').

I have another function which will filter these by Teacher.

The above functions work perfectly fine but instead of returning True for every classes average age that matches the supplied age.. I want to return True for every age than is equal or greater than the supplied age.

I hope you can help, thanks, Alex./

No correct solution

OTHER TIPS

First of: I am not sure if I understood your functions correctly. If they are supposed to do something different than I assumed let me know.

Let's start by doing some 'refactoring' of your code:

In Haskell we do not enclose our argument list in parentheses like in other languages. So

averageMarks list = sum (map snd list) `div` length list

is more idiomatic.

Moving on to your second function.

I suppose you want to write a function which checks whether a single students has exactly the average mark(So you can filter all your students by this predicate for example?).

You are doing this by first computing the average grade of all Students, then putting this single value in a list and then looking if r is in this list. As elem does this by checking for each element if r equals this element, this line means exactly the same as 'does r equal the average grade'. So you can change this line to

| r == averageMark students = True

Another thing that is not optimal is that you are checking a condition which already gives you a boolean value to decide whether you should return True or False. So why not use this value directly:

filterAverageMarks :: Int -> Class -> Bool
filterAverageMarks r (teacher, assistant, code, students) = r == averageMark students

A last refactoring: You are never using teacher, assistant, and code. You can make this clear by replacing those variables by _. So your code becomes:

filterAverageMarks :: Int -> Class -> Bool
filterAverageMarks r (_, _, _, students) = r == averageMark students

Now we will finally look at your real question.

What you want to do is to check whether the average grade is bigger or equal your given grade r(I hope I did understand your intention here correctly).

The mistake lies in the line

where n >= r

I think you are trying to use the where to say something like: Let n be all values greater or equal r. This is not what a where does. where bindings are used to declare functions which are only visible to the function the where is attached to. So you can have helper functions only needed in one function not clatter the global namespace.

If you would want to go this way for a solution you could build an infinite list all n >= r, but I advise against that.

Instead do it in a similar way I suggested as a refactoring in your second function. Replace the fiddling with lists and elem by straight up comparing. After also applying the same refactorings as before you should get:

filterAverageMarks :: Int -> Class -> Bool
filterAverageMarks r (_, _, _, students) = r <= averageMark students

This should do the job fine.

I hope I could help you and understood you right.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top