2017-07-13 70 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