简体   繁体   English

F#成员对返回类型的约束

[英]F# member constraints on return type

Suppose I have following types: 假设我有以下几种类型:

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 
}

Following two functions are to build the addresses: 以下两个功能用于构建地址:

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

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

Following function is to build the PersonData: 以下功能是构建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

For above function, the return type is inferred as PersonDataHigh by F#. 对于上述功能,F#将返回类型推断为PersonDataHigh Hence, to return different types for PersonData(ie PersonDataHigh and PersonDataLow ) I have to write two different functions. 因此,要为PersonData返回不同的类型(即PersonDataHighPersonDataLow ),我必须编写两个不同的函数。

Another approach is to use discriminated unions(DU) but that involves number of conversions back and forth between DU type and case-identifiers of the DU type. 另一种方法是使用区分联合(DU),但涉及DU类型和DU类型的案例标识符之间来回转换的次数。

Is it possible to use constraints for the return type so as to write the function just once? 是否可以对返回类型使用约束以便只编写一次函数? Say, something like this: 说,像这样:

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()
    }

If not, is using DU the best choice here? 如果不是,使用DU是这里的最佳选择吗? I am using F# 3.0. 我正在使用F#3.0。

Thanks. 谢谢。

Have you thought about nesting the low or highness within a single Address type? 您是否考虑过将低位或高位嵌套在单个Address类型中?

Since you most of the data is shared between the two types of Address , I don't think making it a discriminated union or two different types is the most sensible option. 由于大多数数据都是在两种类型的Address之间共享的,所以我认为将其设为一个有区别的联合或两种不同的类型不是最明智的选择。 Instead, just make one of its properties a disciminated union. 相反,只需使其属性之一成为有区别的联合。

The simplest way to do this is make the AreaName an option . 最简单的方法是将AreaNameoption

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

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

Then you can go: 然后您可以去:

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

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

You then don't need anything fancy to create your GetPerson function. 然后,您不需要花哨的时间即可创建GetPerson函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM