-1

I have defined two data type.

type LastName = String 
type FirstName = String
type CodeP = Int 
type CodeS = String
type CodeI = Int
type GroupNb = Int
type Session = Int

Data Inscription = Inscription CodeS GroupNb Session deriving (Show, Eq)
Data Student = Student CodeS LastName FirstName CodeP

I wanna get a list of all the GroupNb that a student followed during the Session 1. My issue is that I don't know how to pass those 2 data types as arguments of the wanted function. Here are the functions I wrote (not working) :

getCodeS :: Student -> CodeS
getCodeS (Student codeS _ _ _) = codeS

check :: Inscription -> Student -> Bool 
check (Inscription codeS _ Session) = codeS == (getCodeS Student) && Session == 1  

filterGroups :: [Inscription] -> Student -> [Inscription]
filterGroups g = filter check g Student

getGroupNb :: Inscription -> GroupNb
getGroupNb (Inscription _ groupNb _) = groupNb

stuGroupNb :: [Inscription] -> Student -> [groupNb]
stuGroupNb groupX = map getGroupNb (filterGroups groupX Student)

So, I'm trying to pass Student as a parameter to many functions, but it is not working.

How can I pass two data types parameter to a function?

Caro
  • 21
  • 7

1 Answers1

2

You aren't passing a student value to each student (at least, not explicitly); you are trying to use the data constructor in the definition of the functions. (In fact, you are confusing data constructors with passed values in several places.) For example, here is a correct definition of check that given an Inscription value and a Student value, returns whether the given student is enrolled during session 1.

check :: Inscription -> Student -> Bool
check (Inscription codeS _ session) student = codeS == (getCodeS student) && session == 1

Notice the use of student as the second argument to check. Also, session is the name of a variable to bind during the pattern match, not the type alias defined earlier, so it must start with a lowercase letter. Since the session is hard-coded to 1 here, you could pattern match on that instead of including a separate comparison in the body:

check :: Inscription -> Student -> Bool
check (Inscription codeS _ 1) student = codeS == (getCodeS student)
check _ _ = False

For filterGroups :: [Inscription] -> Student -> [Inscription], the correct definition would then be filterGroups g student = filter (\x -> check x student) g. Because of this, a better definition for check would be to swap the arguments, so that check :: Student -> Inscription -> Bool could be used like this:

filterGroups g student = filter (check student) g

Without changing check, you could use flip, but that would make it harder to read:

filterGroups g student = filter ((flip check) student) g
chepner
  • 389,128
  • 51
  • 403
  • 529
  • Actually, this does not take a list as a first argument. – chi Mar 13 '16 at 18:43
  • Good point. Looks like that's the intention, based on how it is used `filterGroups`. – chepner Mar 13 '16 at 19:02
  • Yes, that's correct, it is actually not supposed to be a list. I will edit my post. – Caro Mar 13 '16 at 19:05
  • @chepner Your solution worked , thanks for the explanation. The only function I cannot get to work is filterGroups. I changed the second line for `filterGroups g student = filter check g student` but it says it couldnt match expected type. – Caro Mar 13 '16 at 19:09
  • @chepner Thank you !! If I swap the arguments in the check function, should I also swap the command.. something like : `check student (Inscription codeS _ session) = codeS == (getCodeS student) && session == 1` or the order isnt important ? – Caro Mar 13 '16 at 19:20
  • That's exactly what I meant. The type signature indicates the order in which the function receives its arguments. – chepner Mar 13 '16 at 20:40