6

在我的 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 上使用单个变量进行模式匹配似乎很明显应该是有效的 - 所以我想知道是否有人知道这种奇怪行为的原因,或者你是否像我一样认为这是一个错误。

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

> Foo;;
val it : string * int -> foo = <fun:clo@14-1>
> Bar;;
val it : string * int -> bar = <fun:clo@13>

所以当然,他们应该接受相同的一组有效模式

4

1 回答 1

6

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

  • 在 的情况下Foo,该案例包含一个类型的元素int * string
  • 如果是Bar,则 case 包含两个元素 typeintstring

这两个选项非常相似,但它们实际上是不同的。如果您查看F# 规范中的类型定义,就会发现这一点。以下是描述可区分联合的类型定义的位:

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

联合类型案例 :=
   '|' 选择 联合类型案例'|' ...'|' 联合类型案例

union-type-case :=
   属性选择   union-type-case-data

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

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

type :=
   ( type )
   type -> type -- 函数类型
   type * ... * type -- 元组类型
   ... -- 许多其他类型

我不知道为什么union-type-case-data不只使用一元联合案例(而不是 n-ary)并且总是将元素视为元组。我认为这很有意义,但它可能是 F# 从 OCaml 或 ML 继承的东西。但是,至少规范解释了这一点!

事实上,我认为规范有点模棱两可,因为您可以将Foo of int * int元组视为 n 元联合情况和一元情况(但没有括号中的 type ( type ))。

于 2012-08-23T10:10:00.803 回答