在具有相同标签的不同F#记录类型上执行相同的功能

时间:2017-05-29 12:13:40

标签: f# record

假设我有以下记录类型及其列表:

type Employee = {            
    id:int
    name:string
}

type Project = {            
    id:int
    name:string
}

let el = [{Employee.id = 1; name = "E1"};{Employee.id = 2; name = "E2"};{Employee.id = 3; name = "E3"};]
let pl = [{Project.id = 5; name = "P1"};{Project.id = 6; name = "P2"};{Project.id = 7; name = "P3"};]

我想将相同的函数(如下定义)应用于两个类型列表,但推断的类型是Project。

let CreateFormattedStringList l =
    l |> List.map(fun x -> (x.id |> string) + "@" + x.name)
//function signature:
//val CreateFormattedStringList : l:Project list -> string list

let res_1 =  el |> CreateFormattedStringList //error
let res_2 =  pl |> CreateFormattedStringList //ok

我发现这个有用的link显示了返回的简单值。因此,在我的情况下,以下两种类型的列表都适用:

let inline CreateFormattedStringList (l: ^T list) =
    (^T: (member id:int) (l.Head))

现在我无法围绕如何以相同的方式应用更复杂的功能。类似的东西:

let inline CreateFormattedStringList (l: ^T list) =
    l |> List.map(fun (^T: (member id:int) (x)) -> (x.id |> string) + "@" + x.name)
//error

我正在尝试寻找示例,但无法做到。如何使用内联才能将相同的功能应用于这两种类型?另外,如何添加名称'并且' id'既?

1 个答案:

答案 0 :(得分:2)

首先,我认为编写一个适用于单个项而不是列表的函数更简单,然后在必要时将其与其他更高阶函数(如List.map)一起使用。

这种语法令人困惑,但到目前为止你所使用的实际上是一个函数,它包含一个使用id成员的表达式,同时还断言输入类型有一个id成员。所以你需要为name添加另一个表达式。如果将这些名称绑定到名称上,则更容易分辨:

let inline formatIdName (x: ^T) =
    let id = (^T: (member id:int) x)
    let name = (^T: (member name:string) x)
    sprintf "%i - %s" id name

formatIdName {Employee.id = 1; name = "E1"} // "1 - E1"
formatIdName {Project.id = 5;  name = "P1"} // "5 - P1"