模式匹配 SML 中的列表
Pattern Matching a List in SML
假设我创建了一个学生记录对象,它是一个包含 (studentID,name,midtermScore,finalScore) 的元组。然后我可以使用模式匹配来创建使用该对象的函数。例如,return基于学生记录的综合分数的函数:
fun score (studentID,name,midtermScore,finalScore) =
( 0.4 * (midtermScore) ) + ( 0.6 * (finalScore) )
现在假设我想创建另一个函数,它对这些学生记录对象的整个 list 进行操作,这个函数将采用这样的列表,并且 return包含每个记录对象的学生 ID 及其综合分数的新列表。例如:
fun scores ( [studentID,name,midtermScore,finalScore] ) =
map(fn x => (studentID,score(x)))
我也可以在语法上以其他方式实现此功能,这些方式也使用模式匹配,但我遇到的问题是代码编译时,它永远不会生成我正在寻找的绑定。例如,上面的 scores 函数生成这些绑定:
val scores = fn : 'a list -> ('b * 'c * real * real) list -> ('a * real) list
而我想要实现的是:
val scores = fn : ('a * 'b * real * real) list -> ('a * real) list
我知道造成这种差异的原因是我将学生记录对象列表作为 scores 函数的参数进行模式匹配。
有人可以从语义上解释为什么我得到了我得到的绑定,以及我需要如何修改 scores 函数才能生成所需的绑定?
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)))
这不是列表模式匹配的工作方式。
首先,这里是我如何将学生表示为具有 named 字段(记录)而不是 numbered 字段(元组)的记录:
datatype student = Student of {
studentID : int,
name : string,
midtermScore : real,
finalScore : real
}
不一定要用datatype
,你也可以写成type student = { ... }
.
然后编写一些辅助函数,如果我不使用 datatype
,这些是可以避免的,因为这样我就可以简单地使用 #name
,因为我可以编写 #1
, #2
用于访问编号的元组字段:
fun studentScore (Student { midtermScore = midtermScore, finalScore = finalScore, ... }) =
(0.4 * midtermScore) + (0.6 * finalScore)
fun studentName (Student { name = name, ... }) = name
我能够使用 map
:
生成 (name, score) 元组的列表
fun studentScores students =
map (fn student => (studentName student, studentScore student)) students
如果您只是想坚持使用元组并对列表进行递归和模式匹配,您可以这样做:
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
您会注意到,通过适当的抽象,实现可能并不重要。
假设我创建了一个学生记录对象,它是一个包含 (studentID,name,midtermScore,finalScore) 的元组。然后我可以使用模式匹配来创建使用该对象的函数。例如,return基于学生记录的综合分数的函数:
fun score (studentID,name,midtermScore,finalScore) =
( 0.4 * (midtermScore) ) + ( 0.6 * (finalScore) )
现在假设我想创建另一个函数,它对这些学生记录对象的整个 list 进行操作,这个函数将采用这样的列表,并且 return包含每个记录对象的学生 ID 及其综合分数的新列表。例如:
fun scores ( [studentID,name,midtermScore,finalScore] ) =
map(fn x => (studentID,score(x)))
我也可以在语法上以其他方式实现此功能,这些方式也使用模式匹配,但我遇到的问题是代码编译时,它永远不会生成我正在寻找的绑定。例如,上面的 scores 函数生成这些绑定:
val scores = fn : 'a list -> ('b * 'c * real * real) list -> ('a * real) list
而我想要实现的是:
val scores = fn : ('a * 'b * real * real) list -> ('a * real) list
我知道造成这种差异的原因是我将学生记录对象列表作为 scores 函数的参数进行模式匹配。
有人可以从语义上解释为什么我得到了我得到的绑定,以及我需要如何修改 scores 函数才能生成所需的绑定?
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)))
这不是列表模式匹配的工作方式。
首先,这里是我如何将学生表示为具有 named 字段(记录)而不是 numbered 字段(元组)的记录:
datatype student = Student of {
studentID : int,
name : string,
midtermScore : real,
finalScore : real
}
不一定要用datatype
,你也可以写成type student = { ... }
.
然后编写一些辅助函数,如果我不使用 datatype
,这些是可以避免的,因为这样我就可以简单地使用 #name
,因为我可以编写 #1
, #2
用于访问编号的元组字段:
fun studentScore (Student { midtermScore = midtermScore, finalScore = finalScore, ... }) =
(0.4 * midtermScore) + (0.6 * finalScore)
fun studentName (Student { name = name, ... }) = name
我能够使用 map
:
fun studentScores students =
map (fn student => (studentName student, studentScore student)) students
如果您只是想坚持使用元组并对列表进行递归和模式匹配,您可以这样做:
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
您会注意到,通过适当的抽象,实现可能并不重要。