理解F#StringConstant

时间:2013-05-31 14:24:01

标签: f#

我试图理解以下代码,特别是StringConstant:

type StringConstant = StringConstant of string * string 

[<EntryPoint>]
let main argv = 
    let x = StringConstant("little", "shack")
    printfn "%A" x

    0 // return an integer exit code

(通过上下文,在FParsec tutorial中使用StringConstant,但此示例不使用FParsec。)

我想知道的是:

  1. 类型语句到底在做什么?

  2. 一旦我实例化了x,我将如何访问各个“部分” (“小”或“房子”)

4 个答案:

答案 0 :(得分:7)

正如其他人已经注意到的那样,从技术上讲,StringConstant是一个只有一个案例的歧视联盟,你可以使用模式匹配来提取值。

在谈论F#中的domain modelling时,我喜欢使用另一种有用的类比。通常,您可以通过说某些数据类型是元组来开始:

type Person = string * int

这是表示数据的简单方法,但问题是当您编写"Tomas", 42时,编译器不知道您的意思是Person,而是将其理解为string * int元组。一个案例歧视的工会是命名你的元组的一种非常好的方式:

type Person = Person of string * int

使用名称Person两次可能有点令人困惑 - 首先是类型名称,第二个是案例名称。这没有特殊意义 - 它只是意味着该类型将与案例具有相同的名称。

现在您可以编写Person("Tomas", 42)来创建一个值,它的类型为Person。您可以使用matchlet对其进行分解,但您也可以轻松编写带Person的函数。例如,要返回名称,您可以写:

let getName (Person(name, _)) =  
  name

我认为单一案例歧视联盟经常被使用,主要是因为它们很容易定义并且非常容易使用。但是,我不会在作为公共API公开的代码中使用它们,因为它们有点不寻常并且可能令人困惑。

PS:另请注意,在提取值时需要使用括号:

// Correct. Defines symbols 'name' and 'age'
let (Person(name, age)) = tomas 

// Incorrect! Defines a function `Person` that takes a tuple 
// (and hides the `Person` case of the discriminated union)
let Person(name, age) = tomas

答案 1 :(得分:2)

StringConstant是一种有区别的联合类型,只有一个案例(也称为StringConstant)。您可以使用match / function或仅let通过模式匹配来提取零件,因为只有一个案例:

let (StringConstant(firstPart, secondPart)) = x

答案 2 :(得分:1)

type StringConstant = StringConstant of string * string 

导致一种类型的歧视联合。

如果您在F#interactive中执行它,请

type StringConstant = | StringConstant of string * string

您可以在here上看到msdn文档。

您可以像这样获得价值:

let printValue opt =
    match opt with
    | StringConstant( x, y) -> printfn "%A%A" x y

答案 3 :(得分:1)

其他人已经提到你如何从一个受歧视的联盟中提取数据,但是为了更多地阐述歧视联盟,人们可以说它们就像类固醇的枚举一样。它们在幕后实现为类型层次结构,其中类型是基类,案例是该基类的子类,它们可能具有作为只读公共变量的任何参数。

在Scala中,类似的数据结构称为案例类,可以帮助您说服自己这种实现方法。

有区别的联合的一个不错的属性是它们是可自引用的,因此非常适合定义像树一样的递归结构。以下是仅在三行代码中的霍夫曼编码树的定义。在C#中执行此操作可能需要5到10倍的代码行。

type CodeTree =
     | Branch of CodeTree * CodeTree * list<char> * int
     | Leaf of char * int

有关歧视联盟的信息,请参阅msdn documentation

有关使用Discriminated Unions作为树结构的示例,请参阅此gist,它是大约60行F#中的霍夫曼解码器的实现。