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

时间:2012-08-23 09:09:52

标签: types f# 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
> 

我觉得Foo和Bar上的模式匹配单个变量应该是有效的 - 所以我想知道是否有人知道这种奇怪行为的原因,或者如果你喜欢我认为它是一个bug。

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

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

当然,他们应该接受同一套有效模式

1 个答案:

答案 0 :(得分:6)

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

  • 如果是Foo,则案例包含一个int * string
  • 类型的元素
  • 如果是Bar,则案例包含intstring
  • 类型的两个元素

这两个选项非常相似,但它们实际上是不同的。如果你看the type definitions in the F# specification,你可以看到。以下是描述区别联合的类型定义的位:

  

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

     

union-type-cases:=
  '|' opt union-type-case'|' ......'|' union-type-case

     

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

     

union-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 ))。