3

我正在尝试理解以下代码,尤其是 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 教程中使用了 StringConstant ,但本示例未使用 FParsec。)

我想知道的是:

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

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

4

4 回答 4

7

正如其他人已经指出的那样,从技术上讲,StringConstant它是一个只有一个案例的有区别的联合,您可以使用模式匹配来提取值。

在谈论F# 中的域建模时,我喜欢使用另一个有用的类比。通常,您可以从说某些数据类型是元组开始:

type Person = string * int

这是一种非常简单的数据表示方式,但问题是,当你编写 时"Tomas", 42,编译器并不知道你的意思Person,而是将它理解为string * int元组。单例区分联合是命名元组的一种非常好的方法:

type Person = Person of string * int

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

现在你可以写Person("Tomas", 42)来创建一个值,它会有一个 type Person。您可以使用matchor对其进行分解let,但您也可以轻松编写采用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
于 2013-05-31T14:35:42.947 回答
2

StringConstant是一个可区分的联合类型,只有一个案例(也称为StringConstant)。您可以通过模式匹配提取部分,使用match/function甚至只是let,因为只有一个案例:

let (StringConstant(firstPart, secondPart)) = x
于 2013-05-31T14:29:41.337 回答
1
type StringConstant = StringConstant of string * string 

导致一种类型的有区别的联合。

type StringConstant = | StringConstant of string * string如果你在 F# 交互中执行它。

您可以在此处查看 msdn 文档。

您可以像这样获取值:

let printValue opt =
    match opt with
    | StringConstant( x, y) -> printfn "%A%A" x y
于 2013-05-31T14:30:28.237 回答
1

其他人已经提到了如何从有区别的联合中提取数据,但要详细说明有区别的联合,可以说它们有点像类固醇上的枚举。它们在幕后实现为类型层次结构,其中类型是基类,而案例是该基类的子类,它们可能具有作为只读公共变量的任何参数。

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

可区分联合的一个很好的特性是它们是自引用的,因此非常适合定义像树这样的递归结构。下面是仅用三行代码定义的霍夫曼编码树。在 C# 中这样做可能需要 5 到 10 倍的代码行数。

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

有关区分联合的信息,请参阅msdn 文档

有关使用区分联合作为树结构的示例,请参阅此要点,它是在大约 60 行 F# 中实现霍夫曼解码器)

于 2013-05-31T14:46:14.100 回答