问题描述
假设我创建了一个学生记录对象,它是一个由 (studentID,name,midtermscore,finalscore) 组成的元组。然后我可以使用模式匹配来创建使用这个对象的函数。例如,一个根据学生记录返回综合分数的函数:
fun score (studentID,finalscore) =
( 0.4 * (midtermscore) ) + ( 0.6 * (finalscore) )
现在假设我想创建另一个函数,该函数对这些学生记录对象的整个列表进行操作,该函数将采用这样一个列表,并返回一个包含每条记录的学生 ID 的新列表对象,及其综合得分。例如:
fun scores ( [studentID,finalscore] ) =
map(fn x => (studentID,score(x)))
我也可以在语法上以其他方式实现这个函数,这些方式也使用模式匹配,但我遇到的问题是代码编译时,它永远不会生成我正在寻找的绑定。例如,上面的 scores 函数会生成这些绑定:
val score = fn : 'a list -> ('b * 'c * real * real) list -> ('a * real) list
而我想要实现的是:
val score = fn : ('a * 'b * real * real) list -> ('a * real) list
我知道导致这种差异的原因是我将学生记录对象列表模式匹配为 scores 函数的参数。
有人可以解释语义明智的为什么我得到我得到的绑定,以及我需要如何修改 scores 函数以生成所需的绑定?
解决方法
现在假设我想创建另一个函数,该函数对这些学生记录对象的整个列表进行操作,该函数将采用这样一个列表,并返回一个包含每个记录对象的 studentID 及其综合分数的新列表。例如:
fun scores ( [studentID,name,midtermScore,finalScore] ) =
map(fn x => (studentID,score(x)))
列表上的模式匹配不是这样工作的。
首先,这里是我如何将学生表示为具有命名字段(记录)而不是编号字段(元组)的记录:
datatype student = Student of {
studentID : int,name : string,midtermScore : real,finalScore : real
}
并非绝对必须使用 datatype
,您也可以编写 type student = { ... }
。
然后编写一些如果我不使用 datatype
可以避免的辅助函数,因为这样我就可以简单地使用 #name
,因为我可以编写 #1
,{{ 1}} 用于访问带编号的元组字段:
#2
我可以使用 fun studentScore (Student { midtermScore = midtermScore,finalScore = finalScore,... }) =
(0.4 * midtermScore) + (0.6 * finalScore)
fun studentName (Student { name = name,... }) = name
生成 (name,score) 元组列表:
map
如果您只是想坚持使用元组并在列表上进行递归和模式匹配,您可以这样做:
fun studentScores students =
map (fn student => (studentName student,studentScore student)) students
您会注意到,如果抽象数量合适,实现可能并不重要。