理解F#StringConstant

Jon*_*ats 3 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
Run Code Online (Sandbox Code Playgroud)

(通过上下文,StringConstant用于FParsec教程,但此示例不使用FParsec.)

我想知道的是:

  1. 类型语句究竟在做什么?

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

Tom*_*cek 7

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

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

type Person = string * int
Run Code Online (Sandbox Code Playgroud)

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

type Person = Person of string * int
Run Code Online (Sandbox Code Playgroud)

这可能有点令人困惑,因为它使用了Person两次名称- 首先作为类型名称,然后作为案例名称.这没有特殊意义 - 它只是意味着类型将与案例具有相同的名称.

现在你可以编写Person("Tomas", 42)创建一个值,它将有一个类型Person.您可以使用match或分解它let,但您也可以轻松编写所需的函数Person.例如,要返回名称,您可以编写:

let getName (Person(name, _)) =  
  name
Run Code Online (Sandbox Code Playgroud)

我认为单一案例的歧视联盟经常被使用,主要是因为它们很容易定义并且非常容易使用.但是,我不会在作为公共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
Run Code Online (Sandbox Code Playgroud)