To start with I have created a Type StudentMark which is a tuple taking firstly a String and secondly an Int.
type StudentMark = (String, Int)
This is my capMarks function:
capMarks :: [StudentMark] -> [StudentMark]
capMarks [cMarks] = [(st, mk) | (st, mk) <- [capMark cMarks]]
And here is my capMark function:
capMark :: StudentMark -> StudentMark
capMark (st, mk)
| mk > 39 = (st, 40)
| mk < 40 = (st, mk)
It is supposed to return:
[("Jo", 37), ("Sam", 40)]
from:
capMarks [("Jo", 37), ("Sam", 76)]
But will only return the correct and expected response when I input just 1 parameter into the function, for example:
capMarks [("Jake", 50)]
Or
capMarks [("Jake"), 30]
But using two (or more) as it's supposed to will just tell me there is a Non-exhaustive pattern in the capMarks function.
Let's analyze your capMarks
function:
capMarks :: [StudentMark] -> [StudentMark]
capMarks [cMarks] = [(st, mk) | (st, mk) <- [capMark cMarks]]
First of all capMarks [cMarks] = ...
is a pattern matching. This matches a list that contains a single element. I assume that you want to do something with an entire list, so change this to capMarks cMarks = ...
Next ... [(st, mk) | (st, mk) <- [capMark cMarks]]
will apply the capMark
function to the only element in your original pattern matching scheme and then put the result as the only element of a list. It appears that you want to apply capMark
to each element of a list. So if we follow the previous suggestion, you need to do something like ... [capMark mark | mark <- cMarks]
. This does exactly as stated earlier: apply capMark
to each element of the cMarks
list.
Final version:
capMarks :: [StudentMark] -> [StudentMark]
capMarks cMarks = [capMark mark | mark <- cMarks]
Alternatively, you can also use pattern matching and explicit recursion:
capMarks [] = []
capMarks (x:xs) = capMark x : capMarks xs
The first line says that capMarks
applied to an empty list is an empty list. The second line says that capMarks
applies to a list with at least one element will apply capMark
to the first element and then recursively apply capMarks
to the rest of the list.
This is such a common pattern in Haskell that there is a function called map
that generalizes it. Using map
is incredibly simple:
capMarks cMarks = map capMark cMarks
map
has type (a -> b) -> [a] -> [b]
which means it takes a function and a list and returns a list. (The a
and b
just tell the compiler which types have to be the same.) map
then applies the function to each element in the input list.
Eventually you will learn about partial function application and point-free style. With these two concepts, the version using map
can be simplified slightly:
capMarks = map capMark
Don't worry too much about this yet. I'm just adding it here for completeness.