模式匹配中的部分解构 (F#)

5

以下是一个关于观察的最简单示例(让我感到惊讶):

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)" 表示完全相同的类型,因此在任何代码片段中,一个可以替换成另一个(参考透明性)...但正如我们所见,这并不是真的。

此外,似乎很重要的是,为了解释手头的行为,我们不得不讨论 "编译后某些代码的样子" 而不是语言语义的语义属性,这表明语言语义与编译器实际执行的操作之间存在一些 "紧张关系"。


1
尝试使用 type Vector = V of (float*float),让编译器使用实际的元组来表示内容。 - kvb
它能工作!但是它怎么可能有所不同呢?我的意思是 type Vector = (V of float)*float 甚至都不合法吗? - D.F.F
1
问题是:V of x*y 是指“V包含类型为x和y的项目元组”还是“V包含两个不同类型的字段x和y”?如果您不使用括号表示元组,则编译器会认为是后者,但如果您使用括号,则意味着前者。这种区别主要与其他.NET语言的互操作性有关,但正如您发现的那样,在某些情况下它也会影响您在F#中与此类类型的值交互的方式。 - kvb
谢谢您的评论,请查看我的编辑。 - D.F.F
1个回答

2
在 F# 中
type Vector = V of float*float

这只是一个退化的联合体(在Visual Studio中将其悬停可以看到),因此它等价于:
type Vector = 
    | V of float*float

“of”后面的部分创建了两个匿名字段(如F#参考所述)和一个接受两个float类型参数的构造函数。
如果您定义
type Vector2 = 
    | V2 of (float*float)

只有一个匿名字段,它是一个浮点数元组和一个带有单个参数的构造函数。正如评论中指出的那样,您可以使用 Vector2 来进行所需的模式匹配。
在所有这些之后,以下代码似乎是不合逻辑的:
let argsTuple = (1., 1.)
let v1 = V argsTuple

然而,如果考虑到有一个隐藏的模式匹配,一切都应该很清楚。
编辑: F# 语言规范(第122页) 明确指出括号在联合定义中非常重要:
引用: 括号在联合定义中非常重要。因此,以下两个定义不同: type CType = C of int * int type CType = C of (int * int) 第一个示例中缺少括号,表明联合情况需要两个参数。第二个示例中的括号表示联合情况需要一个一级元组值作为参数。
我认为这种行为与您可以在联合定义中定义更复杂的模式是一致的,例如:
    type Move = 
        | M of (int * int) * (int * int)

“能够使用多个参数的联合也非常有意义,特别是在互操作情况下,当使用元组很麻烦时。”
“你使用的另一件事:”
type Vector = int * int

是一个类型缩写, 它仅仅给某种类型命名。在int * int周围加上括号没有任何影响,因为这些括号将被视为分组括号。

我(理解并)同意你所说的一切,并且我将接受那个答案。然而,我仍然认为,在设计上,联合定义中括号的作用更多地是实用而不是干净/优雅的一面;)。有些联合定义中可能会有一些括号用于分组,而其他括号则如前所述...形式为“...= X of Y”的进一步定义不仅取决于Y“作为类型”... - D.F.F
我同意,从语法角度来说,这不是最直观和干净的设计选择;另一方面,它也不太优美。 - Tomasz Maczyński

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接