2013-05-31 66 views
3

我想明白下面的代碼,特別是StringConstant:瞭解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 

(通過上下文的方式,StringConstant在FParsec tutorial使用,但本例中不使用FParsec)

我想知道的是:

  1. 這個類型語句到底在幹什麼?

  2. 一次我實例X,我將如何訪問各個「部件」 (「小」或「房子」)

回答

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 
2

StringConstant是可區分聯合類型,只是一個單一的情況下(也命名爲StringConstant)。你經由模式匹配提取部件,使用match/function甚至只是let,由於只是一個單一的情況下:

let (StringConstant(firstPart, secondPart)) = x 
+1

+1(我不得不刪除我的正在進行的答案的第一段,因爲它正是你寫的:-)) –

1
type StringConstant = StringConstant of string * string 

導致識別聯合與一種類型。

type StringConstant = | StringConstant of string * string如果您在F#interactive中執行它。

您可以在該here上看到msdn文檔。

你可以得到價值出來是這樣的:

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

的其他人已經提到您如何提取可識別聯合數據,但更詳細地說明識別聯合一點人們可以說它們就像類固醇的枚舉一樣。它們在幕後實現爲類型層次結構,其中類型是基類,並且這些案例是該基類的子類,並且具有作爲只讀公共變量的任何參數。

在斯卡拉一個類似的數據結構被稱爲案例類,這可能會幫助你說服你自己這種實施方法。

歧視工會的一個不錯的屬性是,他們是自引用的,因此非常適合定義像樹一樣的遞歸結構。下面是三行代碼中霍夫曼編碼樹的定義。在C#中這樣做可能需要5到10倍的代碼行數。

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

約識別聯合有關信息,請參閱msdn documentation

對於使用識別聯合作爲樹結構看到這gist其爲霍夫曼解碼器的實現在F#的大約60行的一個例子)