Types F#返回类型上的成员约束

Types F#返回类型上的成员约束,types,f#,constraints,Types,F#,Constraints,假设我有以下类型: type AddressLow = { FlatNo: int PinCode: string } type AddressHigh = { FlatNo: int AreaName: string PinCode: string } type PersonDataLow = { id:int name:string address: AddressLow } type Person

假设我有以下类型:

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返回不同的类型(即
PersonDataHigh
PersonDataLow
),我必须编写两个不同的函数

另一种方法是使用判别联合(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


谢谢。

您是否考虑过将低位或高位嵌套在一个
地址
类型中

由于大多数数据是在两种类型的
地址之间共享的,我认为将其作为一个有区别的联合或两种不同的类型不是最明智的选择。相反,只需将其属性之一设为非限制并集

最简单的方法是将
AreaName
设为
选项

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
函数。

您可以使用泛型:
type PersonDataYes泛型,当然。谢谢你,李。不过,出于好奇,在F#中是否可能有带“and”和“or”条件的多成员约束?在我们的例子中,我们必须对High和Low使用不同的类型。我认为泛型可能是李所建议的最简单的解决方案。谢谢