【发布时间】:2011-11-03 07:49:21
【问题描述】:
似乎记录类型要求您声明其成员类型:
type Point = { X:int; Y:int }
它背后的基本原理是(或可能是)什么?
似乎在 F# 中,您可以(几乎)总是在编码时不必定义类型。这让我觉得,这种限制或许有很强的理论基础。是这样吗?
对罗伯特的回应:
我确实理解您的担忧,但在我看来,这似乎是错误的推理。我们来看一个例子:
假设 F# 允许我们定义无类型成员:
type Point = { X; Y; }
您的推理围绕着这样一个事实,人们可以在我们的代码中找到如下内容:
let a = { X=1; y=2 } //(1)
let b = { X="1"; y="2" } //(2)
既然如此,编译器别无选择,只能将Point 定义为(隐式)
type Point = { X:object; Y:object }
现在,您可能不仅要创建记录,还要使用它们。话虽如此,您的代码中可能会有一些地方尝试将 Point 的成员视为整数:
let z = a.X + 2 //ERROR. goes against what is seen in (2)
以及其他您将它们视为字符串的地方:
let w = A.X + "abc" //ERROR. goes against what is seen in (1)
两者都会标记错误,因此即使尝试对记录的成员使用相互不兼容的类型,您也做不到!它们会在某种程度上兼容吗?F# 会发现我们使用的可能不是通用的根类型。
这里的明智之处在于与您所描述的相反
您是否希望字段在移动时突然改变其类型 从一条记录到另一条记录?
从一条记录移动到另一条记录时,记录类型不会更改。在更坏的情况下,可能会发生的情况是 Record 的成员类型将非常通用(更糟糕的是,来自 Object 类型)。
但是,当你编写一个只接受无类型参数的方法时,这与你所冒的风险完全相同!正如我们所知,这在 F# 中是允许的。
所以,除非我在这里遗漏了什么,否则这可能不是您必须在 Records 中定义类型的原因。
【问题讨论】:
-
我认为对您的更新的简短回答归结为“结构比较”,Thomas Petricek 在他的一些材料中提到了这一点。您的场景假定编译器通过该记录的第一个实例推断每个“点”record 的类型,我很确定 F# 编译器不会这样做。
-
我相信我确实在他的一篇关于 SO 的帖子中听说过“结构比较”。但我必须阅读它,因为我对此一无所知。
-
很简单,Thomas 指出的是,记录就像 c# 中的类,元组就像匿名类型。在类中为每个成员指定类型是合理的,或者在在类型级别(而不是在实例级别,这将是运行时绑定)静态推断该类型。
-
不幸的是,他没有在材料中说明我读到的确切原因,他们决定要求输入记录。我可以想象它使编译器的工作变得更容易。
标签: .net f# functional-programming record