在有区别的联合案例中使用元组时,括号的作用是什么?

What is the effect of parenthesis when using tuples in discriminated union cases?

discriminated union syntax as defined by Microsoft 文档不包含括号。以下定义允许我在类型定义中使用字段名称,并且与文档中的语法兼容。

type Node<'T> = L of value:'T | N of value:'T * children:Node<'T> list

这个定义:

type Node<'T> = L of value:'T | N of (value:'T * children:Node<'T> list)

给我错误:

Anonymous type variables are not permitted in this declaration

但是,如果我不使用字段名称,括号也可以:

type Node<'T> = L of 'T | N of ('T * Node<'T> list)

评论 in this change request 提到使用括号和不使用括号之间的区别,但坦率地说,整个讨论都让我头疼。

我的印象是无论是否使用括号我都在定义一个元组,即我希望编译器将它们视为多余的,但显然存在差异。 这是什么?

重新阅读 github 问题,我(认为)我明白了在使用括号的情况下有什么不同。

F# 要求元组的所有组件都进行模式匹配,但括号允许将整个元组作为单个模式进行匹配。即

给出

type DU = DUCase of int * int * int

这行不通:

let tst1 du =
    match du with
    |DUCase c -> ""

但给定:

type DU = DUCase of (int * int * int)

会的。

我会等一下再接受这个作为答案,以防我错了有人纠正我。

更新:我现在纠正了。

这只是重载语法。尽管语法相似,但这两种情况在语义上是不同的。

混淆来自于定义 DU 案例字段 用于定义元组类型的相同语法。

考虑这两种类型:

type A = A of int * string
type B = B of (int * string)

此处,构造函数 A 不包装元组。相反,它有两个字段 - 第一个字段类型 int,第二个字段类型 string。 DU 案例字段可以选择有名称,这就是为什么这也有效:

type A1 = A1 of x: int * y: string

构造函数B,另一方面,没有两个字段。它只有一个字段,并且那个字段的类型是int * string。由于 DU 案例字段可能有名称,我们也可以为该单个字段命名:

type B1 = B1 of t: (int * string)

构造 AA1 类型的值时,您在括号中指定所有字段:

let a = A (42, "foo")

就像在类型声明中一样,这看起来像一个元组,但它不是。这是两个不同的领域。由于 DU 案例字段可能有名称,因此您可以在构造值时使用这些名称。有时不混淆它们或只是为了提高代码可读性是有帮助的:

let a1 = A1 (x = 42, y = "foo")

事实上,DU 案例字段总是有名称的,即使您没有明确指定它们也是如此。省略时,编译器将分配看起来像 ItemN 的名称(如果只有一个字段,则只是 Item)。是的,您可以在构造值时使用它们:

let a = A (Item1 = 42, Item2 = "foo")

另一方面,在构造 B 的值时,您不能为元组元素使用名称,因为元组元素没有名称:

let b = B (42, "foo") // works
let b = B (Item1 = 42, Item2 = "foo") // doesn't compile

但是您可以使用类型为 int * string:

的单个字段的名称
let b = B (Item = (42, "foo"))
let b1 = B1 (t = (42, "foo"))

它与模式匹配的工作方式类似。考虑表达式:

match a with
| A (p, q) -> ...

这里又一次,尽管 (p, q) 看起来像一个元组,但它不是。它不匹配构造函数 A 中的元组。相反,它匹配构造函数的两个字段。没有一个元组。两个字段。

与构造值类似,您可以使用字段名称:

match a with
| A1 (x = p, y = q) -> ...

使用字段名称还可以让您部分匹配:

match a with
| A1 (x = p) -> ...

但是当你匹配 B 时,你有两个选择:

(1) match b with B (x, y) -> ...
(2) match b with B t -> ...

第二个选项与匹配 A 的原因相同:构造函数 B 有一个字段,我们正在匹配该字段。

第一个选项有效,因为模式可以 嵌套 :我们匹配构造函数 B 的单个字段,然后我们匹配它的各个元素相同模式的字段。

当然,您也可以使用字段名称:

match b with B (Item = (x, y)) -> ...
match b1 with B1 (t = (x, y)) -> ...

也许不幸的是,DU 大小写字段的语法与元组的语法如此相似,以至于造成了如此多的混淆,但我们就是这样。要记住的底线是:这些不是元组,它只是一个相似的语法。