为什么括号在F#类型声明中很重要

plc*_*plc 6 f# types pattern-matching

在我的F#代码中观察到这种行为,我完全感到困惑,这里是从交互式会话中获取的:

Microsoft (R) F# 2.0 Interactive build 4.0.40219.1
Copyright (c) Microsoft Corporation. All Rights Reserved.

For help type #help;;

> type foo = Foo of (string * int);;
  type foo = | Foo of (string * int)

> let f = Foo ("bar",42);;
  val f : foo = Foo ("bar", 42)

> match f with Foo x -> x;;
  val it : string * int = ("bar", 42)

> type bar = Bar of string * int;;
  type bar = | Bar of string * int

> let b = Bar ("baz",21);;
  val b : bar = Bar ("baz",21)

> match b with Bar x -> x;;
  match b with Bar x -> x;;
  -------------^^^^^

stdin(7,14): error FS0019: This constructor is applied to 1 argument(s) but expects 2
> 
Run Code Online (Sandbox Code Playgroud)

对我来说很明显,Foo和Bar上的模式匹配应该是有效的 - 所以我想知道是否有人知道这种奇怪行为的原因,或者如果你喜欢我认为它是一个bug.

更新:只是为了澄清,报告的类型构造函数的FooBar是:

> Foo;;
val it : string * int -> foo = <fun:clo@14-1>
> Bar;;
val it : string * int -> bar = <fun:clo@13>
Run Code Online (Sandbox Code Playgroud)

当然,他们应该接受同样的有效模式

Tom*_*cek 6

我同意这看起来很混乱.正如pad解释的那样,两个声明之间的区别不仅仅是语法 - 你实际上是在定义由不同类型组成的区别联合案例.

  • 在这种情况下Foo,案例包含一个类型的元素int * string
  • 在这种情况下Bar,案例包含两个类型int和元素string

这两个选项非常相似,但它们实际上是不同的.如果查看F#规范的类型定义,可以看到.以下是描述歧视联合的类型定义的位:

union-type-defn:=
   type-name'='union-type-cases type-extension-elements opt

union-type-cases:=
   '|' 选择 union-type-case'|' ......'|' 联合型的情况下

union-type-case:=
   attributes opt   union-type-case-data

union-type-case-data:=
   ident - null union case case
   of type*...*type - n-ary union case

请注意,"n-ary union case"由多个元素(type * ... * type)组成.甲类型定义如下(不奇怪,它可以是一个元组):

type:=
   (type)
   type - > type - function type
   type*...*type - tuple type
   ... - 许多其他类型

我不知道为什么union-type-case-data不使用一元联合情况(而不是n-ary)并始终将元素视为元组.我认为这将是完全合理的,但它可能是F#从OCaml或ML继承的东西.但是,至少说明书解释了这一点!

事实上,我认为规范有点含糊不清,因为你可以将Foo of int * intn-ary union情况和带有元组的一元情形视为(但没有括号类型( type )).