假设我有以下记录类型及其列表:
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'既?
答案 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"