2017-07-13 115 views
2

假設我有以下幾種類型:F#成員約束

type AddressLow = { 
    FlatNo: int 
    PinCode: string 
} 

type AddressHigh = { 
    FlatNo: int 
    AreaName: string 
    PinCode: string 
} 

type PersonDataLow = {    
    id:int 
    name:string 
    address: AddressLow 
} 

type PersonDataHigh = { //same label names, different type for address 
    id:int 
    name:string 
    address: AddressHigh 
} 

下列兩個功能來構建地址:

let GetAddressLow() = 
    {AddressLow.FlatNo = 10; PinCode = "5245"} 

let GetAddressHigh() = 
    {AddressHigh.FlatNo = 10; AreaName = "Bel Air"; PinCode = "8225"} 

以下功能是建立PersonData:

let GetPerson fGetAddress inputId inputName = //return type inferred as PersonDataHigh 
    { 
     id = inputId 
     name = inputName 
     address = fGetAddress() 
    } 

let p1 = GetPerson GetAddressLow 4 "John Smith" //compile error 
let p2 = GetPerson GetAddressHigh 6 "Will Smith" //works 

對於上述函數,返回類型被F#推斷爲PersonDataHigh。 因此,要返回PersonData的不同類型(即PersonDataHighPersonDataLow),我必須編寫兩個不同的函數。

另一種方法是使用區分聯合(DU),但涉及DU類型和DU類型的病例標識之間來回轉換次數。

是否可以對返回類型使用約束,以便只寫一次函數?說,這樣的事情:

let inline GetPerson (fGetAddress) (inputId) (inputName) 
    : ^T when ^T: (member id: int) and ^T: (member name: string) and (^T: (member address: AddressLow) or ^T: (member address: AddressHigh)) = //compile error 
    { 
     id = inputId 
     name = inputName 
     address = fGetAddress() 
    } 

如果不是,在這裏使用DU的最佳選擇?我正在使用F#3.0。

謝謝。

+6

你可以使用泛型:'type PersonData <'T> = {id:int; name:string;地址:'T}' – Lee

+1

當然是泛型。謝謝李。只是出於好奇,是否可以在F#中使用'和'和'或'條件限制多個成員? – ronilk

回答

6

你有沒有想過在一個單一的Address類型嵌套的低或高?

由於大部分數據是在Address這兩種類型之間共享的,我不認爲將它作爲歧視聯盟或兩種不同類型是最明智的選擇。相反,只要讓它的一個屬性成爲一個廢棄的聯盟。

最簡單的方法是使AreaNameoption

type Address = { 
    FlatNo: int 
    AreaName : string option 
    PinCode: string 
} 

type PersonData = {    
    id:int 
    name:string 
    address: Address 
} 

然後你可以去:

let GetAddressLow() = 
    {FlatNo = 10; AreaName = None; PinCode = "5245"} 

let GetAddressHigh() = 
    {FlatNo = 10; AreaName = Some "Bel Air"; PinCode = "8225"} 

然後你不需要任何花哨的創建您GetPerson功能。

+1

在我們的例子中,我們必須使用不同類型的高和低。我認爲泛型可能是李建議最簡單的解決方案。謝謝。 – ronilk