在我的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
>
我觉得Foo和Bar上的模式匹配单个变量应该是有效的 - 所以我想知道是否有人知道这种奇怪行为的原因,或者如果你喜欢我认为它是一个bug。
更新:
只是为了澄清,构造函数Foo
和Bar
的报告类型是:
> Foo;;
val it : string * int -> foo = <fun:clo@14-1>
> Bar;;
val it : string * int -> bar = <fun:clo@13>
当然,他们应该接受同一套有效模式
答案 0 :(得分:6)
我同意这看起来很混乱。正如pad解释的那样,两个声明之间的区别不仅仅是语法 - 你实际上是在定义由不同类型组成的歧视联合案例。
Foo
,则案例包含一个int * string
Bar
,则案例包含int
和string
这两个选项非常相似,但它们实际上是不同的。如果你看the type definitions in the F# specification,你可以看到。以下是描述区别联合的类型定义的位:
union-type-defn:=
type-name'='union-type-cases type-extension-elements optunion-type-cases:=
'|' opt union-type-case'|' ......'|' union-type-caseunion-type-case:=
attributes opt union-type-case-dataunion-type-case-data:=
ident - null union case
类型* ... *类型的身份 - n-ary union case
请注意,“n-ary union case”由多个元素(type * ... * type
)组成。 类型定义如下(毫不奇怪,它可以是一个元组):
键入:=
(类型)
类型 - &gt;类型 - 功能类型
type * ... * type - 元组类型
...... - 许多其他类型
我不知道为什么 union-type-case-data 不使用一元联合情况(而不是n-ary)并始终将元素视为元组。我认为这将是完全合理的,但它可能是F#从OCaml或ML继承的东西。但是,至少规范解释了这一点!
事实上,我认为规范有点含糊不清,因为你可以将Foo of int * int
视为n-ary union case和带有元组的unary case(但没有括号类型( type )
)。