以下是一个关于观察的最简单示例(让我感到惊讶):
type Vector = V of float*float
// complete unfolding of type is OK
let projX (V (a,_)) = a
// also works
let projX' x =
match x with
| V (a, _) -> a
// BUT:
// partial unfolding is not Ok
let projX'' (V x) = fst x
// consequently also doesn't work
let projX''' x =
match x with
| V y -> fst y
什么原因导致无法与部分解构类型匹配?
一些部分解构似乎是可以的:
// Works
let f (x,y) = fst y
编辑: 好的,我现在明白了所描述的行为的“技术”原因(感谢你们的答案和评论)。然而,从语言上讲,与语言的其他部分相比,这种行为感觉有点“不自然”:
对我来说,在“代数”中,似乎很奇怪将类型“t”与类型“(t)”区分开来。括号(在此上下文中)用于给出类似于“(t * s) * r”与“t * (s * r)”之类的优先顺序。同时,如果我发送
type Vector = (int * int)
或者
type Vector = int * int
对于fsi来说,答案总是
类型 Vector = int * int
基于这些观察,可以得出结论:"int * int" 和 "(int * int)" 表示完全相同的类型,因此在任何代码片段中,一个可以替换成另一个(参考透明性)...但正如我们所见,这并不是真的。
此外,似乎很重要的是,为了解释手头的行为,我们不得不讨论 "编译后某些代码的样子" 而不是语言语义的语义属性,这表明语言语义与编译器实际执行的操作之间存在一些 "紧张关系"。
type Vector = V of (float*float)
,让编译器使用实际的元组来表示内容。 - kvbV of x*y
是指“V包含类型为x和y的项目元组”还是“V包含两个不同类型的字段x和y”?如果您不使用括号表示元组,则编译器会认为是后者,但如果您使用括号,则意味着前者。这种区别主要与其他.NET语言的互操作性有关,但正如您发现的那样,在某些情况下它也会影响您在F#中与此类类型的值交互的方式。 - kvb