2013-06-25 51 views
22

我想在深入研究複雜示例之前弄清楚F#的基本知識。我正在學習的材料引入了歧視聯盟和記錄類型。我已經審查了兩者的材料,但我仍然不清楚爲什麼我們會使用這兩種材料。何時使用歧視聯盟與F#中的記錄類型

我創造的大多數玩具例子似乎都可以在兩者中實現。記錄似乎是非常接近我所認爲的在C#中的對象,但我想避免依賴映射到C#的方式來了解F#

所以......

  • 是有明確的理由使用一個在另一個?

  • 是否存在某些適用的規範情況?

  • 是否有某些功能可用於其中一個,但不是 其他?

+1

本頁面末尾有一個簡短的段落http://msdn.microsoft.com/en-us/library/dd233205.aspx。 –

回答

25

認爲它是一個記錄是'和',而歧視的工會是'或'。 這是一個字符串和一個int:

type MyRecord = { myString: string 
        myInt: int } 

,而這是一個字符串或一個整數,但不能同時一個值:

type MyUnion = | Int of int 
       | Str of string 

這個虛構的遊戲可以在標題畫面,在遊戲中,或顯示最終得分,但只有其中一個選項。

type Game = 
    | Title 
    | Ingame of Player * Score * Turn 
    | Endgame of Score 
+0

那麼,在DU中是否有任何方法來創建一個擴展Game的組合類型?例如| InGameTitle的Title * Ingame。即一個包含Title * Player * Score *的元組* Turn –

+0

@Chris:這隻會引出一個問題:你爲什麼想要? – ildjarn

+0

@ildjarn你是對的。當我第一次寫評論時,我並沒有完全理解DU的目的。 MisterMetaphor先生的回答幫助我理解了爲什麼你會像Robert那樣使用它,但不是如我所述。 –

7

如果你來自C#,你可以瞭解記錄爲密封類與附加價值:

  • 不可改變的默認
  • 結構平等默認
  • 易模式匹配

歧視聯盟編碼替代例如

type Expr = 
    | Num of int 
    | Var of int 
    | Add of Expr * Expr 
    | Sub of Expr * Expr 

的DU上述被讀出如下:表達式是要麼的整數,一個變量,加成兩個表達式或兩個表達式之間減法。這些情況不能同時發生。

您需要所有字段才能構建記錄。您也可以在記錄中使用DU,反之亦然

type Name = 
    { FirstName : string; 
     MiddleName : string option; 
     LastName : string } 

上面的示例顯示中間名是可選的。

在F#中,您經常使用元組或記錄開始建模數據。當需要高級功能時,您可以將它們移動到類上。

另一方面,歧視聯盟用於替代模型和互斥案件之間的關係。

+0

謝謝。這個答案和另一個都指出了DU是一種OR關係的事實。但據瞭解,單個DU可以保存多個值。即「類型名稱」可以具有「FirstName,MiddleName和LastName」的值。這仍然讓我有點不確定,一個具有所有字段值的記錄與一個具有所有字段值的DU之間的區別是什麼。難道DU可以做某種形式的推理或記錄不能做的操作嗎?或者這裏的不變屬性是不同的? –

11

使用記錄複雜的數據(在函數式編程理論所謂的產品類型),這是由幾個屬性描述,如數據庫記錄或一些模型實體:爲

type User = { Username : string; IsActive : bool } 

type Body = { 
    Position : Vector2<double<m>> 
    Mass : double<kg> 
    Velocity : Vector2<double<m/s>> 
} 

使用識別聯合(稱爲總和類型)數據的可能值可以列舉。例如:

type NatNumber = 
| One 
| Two 
| Three 
... 

type UserStatus = 
| Inactive 
| Active 
| Disabled 

type OperationResult<'T> = 
| Success of 'T 
| Failure of string 

注意,對於一個識別聯合值可能值也相互排斥 - 用於操作的結果可以是在同一時間SuccessFailure,但不能同時使用。

你可以使用一個記錄類型的結果編碼的操作,像這樣:

type OperationResult<'T> = { 
    HasSucceeded : bool 
    ResultValue : 'T 
    ErrorMessage : string 
} 

但在操作失敗的情況下,這是ResultValue沒有意義。因此,圖案這種類型的區分聯合版本匹配應該是這樣的:

match result with 
| Success resultValue -> ... 
| Failure errorMessage -> ... 

如果您模式符合我們的操作類型的記錄類型版本,它將使意義不大:

match result with 
| { HasSucceeded = true; ResultValue = resultValue; ErrorMessage = _ } -> ... 
| { HasSucceeded = false; ErrorMessage = errorMessage; ResultValue = _ } -> ... 

它看起來冗長而笨拙,可能效率也不高。我認爲當你有這樣的感覺時,這可能暗示你正在使用錯誤的工具來完成任務。

+0

感謝您的回覆。我現在看到DU在哪裏特別有意義。 –

2

理解一個DU的方法之一就是將它看作一個奇特的C#「union」,而記錄更像是一個普通的對象(具有多個獨立的字段)。

查看DU的另一種方法是將DU視爲一個兩層的類層次結構,其中最上面的DU類型是抽象基類,DU的例子是子類。這個視圖實際上接近實際的.NET實現,儘管編譯器隱藏了這個細節。

+0

OO繼承層次結構的一個重要區別是,DU的不同情況僅僅是標記,而不是不同(子)類型。有時候會讓新人感到困惑。 – Frank