0
votes

Lets say I create a student record object which is a tuple that consists of (studentID,name,midtermScore,finalScore). I can then use pattern matching to create functions that use this object. For example, a function that returns a composite score based on the student record:

fun score (studentID,name,midtermScore,finalScore) = 
     ( 0.4 * (midtermScore) ) + ( 0.6 * (finalScore) )

Now lets say I wanted to create another function which operates on a whole list of these student record objects, this function would take such a list, and return a new list containing the studentID of each record object, and its composite score. For example:

fun scores ( [studentID,name,midtermScore,finalScore] ) = 
     map(fn x => (studentID,score(x)))

I can also implement this function in other ways syntactically which also use pattern matching, but the problem I'm having is while the code compiles, it never generates the bindings I'm looking for. For example, the above scores function generates these bindings:

val scores = fn : 'a list -> ('b * 'c * real * real) list -> ('a * real) list

Whereas what I'm trying to achieve is this:

val scores = fn : ('a * 'b * real * real) list -> ('a * real) list

I know whats causing this discrepancy is in the way that I'm pattern matching the list of student record objects as a parameter to the scores function.

Could someone explain semantics wise why I'm getting the bindings that I'm getting, and how I would need to modify the scores function in order to generate the desired bindings?

1
You can add the types manually if you need it to compile the way you said: fun scores ( [studentID,name,midtermScore,finalScore] : ('a * 'b * real * real) list) user15270287

1 Answers

0
votes

Now lets say I wanted to create another function which operates on a whole list of these student record objects, this function would take such a list, and return a new list containing the studentID of each record object, and its composite score. For example:

fun scores ( [studentID,name,midtermScore,finalScore] ) = 
    map(fn x => (studentID,score(x)))

That's not how pattern matching on lists works.

First, here is how I might represent students as records with named fields (records) rather than numbered fields (tuples):

datatype student = Student of {
  studentID : int,
  name : string,
  midtermScore : real,
  finalScore : real
}

It isn't strictly necessary to use a datatype, you could also write type student = { ... }.

Then writing a few helper functions that were avoidable if I weren't using datatype, because then I could simply use #name as I would be able to write #1, #2 for accessing numbered tuple fields:

fun studentScore (Student { midtermScore = midtermScore, finalScore = finalScore, ... }) =
    (0.4 * midtermScore) + (0.6 * finalScore)

fun studentName (Student { name = name, ... }) = name

I am able to generate a list of (name, score) tuples using map:

fun studentScores students =
  map (fn student => (studentName student, studentScore student)) students

If you simply wanted to stick to tuples and do recursion and pattern matching on lists, you could do:

fun studentScore (_, _, midtermScore, finalScore) =
    (0.4 * midtermScore) + (0.6 * finalScore)

fun studentName (_, name, _, _) =
    name

fun studentScores students =
  map (fn student => (studentName student, studentScore student)) students

You will notice that with the right amount of abstraction, the implementation may not matter much.