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