Record是“each of”类型,先熟悉,然后将它与另一个“each of”类型Tuple对比。
构建
- 语法(syntax)
# Record值是有多个字段,每个字段都持有一个值
{f1 = v1, …, fn = vn}
# Record值是有多个字段,每个字段都持有一个类型
{f1 : t1, …, fn : tn}
# 构建Record
{f1 = e1, ..., fn = en}
注意:
- f可以是任何不重复的字段名称,设置可以是数字,e可以是任何表达式。
- 在ML中使用Record不需要专门去声明其类型(和java、c、python不同),只需要直接使用,类型检查器会推断出正确的类型。
- Record中字段的顺序是不重要的。
- 类型检查(type check):
- 类型检查器会计算每表达式e,以获取正确的值和类型。
- 计算规则(evaluation rules)
Record的计算规则是相似的,计算每个字段的表达式e,产生对应的字段的结果。
使用
{foo : int, bar : int*bool, baz : bool*int}
#foo e
foo是字段名,类型检查器需要e:
- 有record类型
- 有名为foo的字段
如果该字段有类型t,那么#foo e类型即为t。计算e为record值,然后生成foo字段的内容(值)。
实例
{name = "Amelia", id = 41123 - 12}
# 计算为:
{id = 41111, name = "Amelia"}
# 类型为
{id : int, name : string}
Record vs Tuple
record和tuple是非常类似的,它们都是each of类型,并可以包含任意数量的元素。唯一不同的是,record是通过字段名称(即feild)访问其值(注:这也是为何record中元素顺序不重要的原因),而tuple则是通过位置访问其值。
语言设计和使用选择:
record或tuple在某些情况下,都是好的选择。一般有:
- 较少的元素,使用tuple更简洁,方便
- 使用record更容易通过字段名定位元素
- 较大的复杂类型,2优势更明显
在编程语言中,使用位置(类似tuple)还是字段名(类似record)传递参数都是标准的、常见的设计方案,ML函数和java方法中都使用了混合的方式:
- 函数调用者(caller)使用位置传递参数
- 函数被调者(callee)使用参数名获取参数值
语法糖
(* 在REPLE中输入*)
val record_pair = {1 = 1, 2 =2}
(* 输出*)
val record_pair = (1, 2) : int * int
(* 作为record来使用*)
#1 record_pair + #2 record_pair;
(* 打印*)
val it = 3 : int
通过上面的小实验,我们知道在ML中,tuple实际上是特殊的一类record,也可以称tuple是该特殊record的语法糖。
注:语法糖
- “语法的”:即我们可以在语法层面用某种等效的方式(这里指tuple)来描述其相关的所有内容(即特殊的record)。
- “糖:它使编程语法更“甜”,更方便。
- 另外的例子:andalso、orelse vs if ... then ... else ...
该术语被广泛使用,也是将关键思想保留在编程语言中更小巧(更易实现)的一种好方法,同时也为程序员提供了方便的使用方法。
使用record来实现tuple有:
- 表达式:(e1, e2, ..., en)可写为{1=e1, ..., n=en},即一个tuple也是一个字段名为1,2,...,n的record
- 类型:t1 * t2 ... * tn可写为{1:t1, 2:t3, ..., n:tn}
- 上面的表达式#1 e,#2等就表达了正确的事情了:获取字段名1,2等的内容