在有区别的联合案例中使用元组时,括号的作用是什么?
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)
构造 A
或 A1
类型的值时,您在括号中指定所有字段:
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 大小写字段的语法与元组的语法如此相似,以至于造成了如此多的混淆,但我们就是这样。要记住的底线是:这些不是元组,它只是一个相似的语法。
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)
构造 A
或 A1
类型的值时,您在括号中指定所有字段:
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 大小写字段的语法与元组的语法如此相似,以至于造成了如此多的混淆,但我们就是这样。要记住的底线是:这些不是元组,它只是一个相似的语法。