https://cs3110.github.io/textbook/chapters/data/type_synonym.html
正如我们在上面看到的,
type a = int * int * int
type a
是int * int * int
的同义词。
所以,如果我们用多个名称声明
int * int * int
,它们都是相同的类型。
type a = int * int * int
type b = int * int * int
type c = int * int * int
a
和b
和c
是相同的类型。
他们没有数据构造函数。事实上,不需要,也不应该,因为它们只是一个同义词。
但是,当我们看记录时,情况就大不一样了。
type a = { name : string }
type b = { name : string }
type c = { name : string }
a
和b
和c
是不同的类型。
我们可以通过下面的代码来证明它。
({ name = "something" } : a) = ({ name = "something" } : b) ;;
// This expression has type b but an expression was expected of type a
它就像 Haskell 中的“newtype”,没有使用数据构造函数。
听说在OCaml中,记录是一个原始的概念,它们有自己的身份。 (你可以从下面的网址看到它。)
如果那样,为什么元组和记录的行为不同??
这让我很困惑。
了解到记录格式重复的问题可以通过使用模块来解决。 所以这种混乱没什么大不了的。
但是我想知道为什么元组和记录之间存在不一致
主要是类型推断。当你写一个函数
let f x = x.a
然后类型系统将无法判断
f
的类型,如果它可以是任何带有字段a
的记录类型。
有解决歧义的方法,即行多态性,这是 OCaml 用于推断对象类型的方法:
let f o = o#a (* infers type f : < a : 'a; .. > -> 'a *)
在这里,
<a : t; ..>
表示具有a
类型t
的任何对象类型。然而,缺点是这种灵活性需要更重量级和昂贵的对象运行时表示。
也就是说,OCaml 的姊妹语言 Standard ML 确实使记录和元组成为同一件事(字面意思是,
a * b * c
只是 SML 中 {1 : a, 2 : b, 3 : c}
的简写),但随后需要程序员将类型注释插入到解决可能的歧义,如上例所示。