我有两种JsonProvider类型:
CROSS JOIN UNNEST
我想要一个函数,它可以接受任何这些并使用提供的JsonProvider解析json,如下所示:(伪代码,不编译)
type Provider1 = JsonProvider<"""{structure}""">
type Provider2 = JsonProvider<"""{}structure2""">
答案 0 :(得分:2)
您可以使用静态分辨类型参数(SRTP)定义内联函数:
let inline parseUsingSpecificProvider json (provider:^T) =
(^T : (static member Parse : string -> _) json)
// tests
#r @"packages\FSharp.Data\lib\net40\FSharp.Data.dll"
open FSharp.Data
type Provider1 = JsonProvider<""" { "name":"John" } """>
type Provider2 = JsonProvider<""" { "name":"John", "age":94 } """>
let x = parseUsingSpecificProvider (""" { "name":"Tomas", "age":4 } """) Unchecked.defaultof<Provider1>
let y = parseUsingSpecificProvider (""" { "name":"Tomas", "age":4 } """) Unchecked.defaultof<Provider2>
因此它适用于任何具有静态方法Parse
接受字符串作为输入的类型。
答案 1 :(得分:0)
在函数式编程中,通常用函数本身替换“单个函数接口”。即而不是传递具有Parse
方法的解析器,只需使用Parse
函数作为第一类值:
#r @"packages\FSharp.Data\lib\net40\FSharp.Data.dll"
open FSharp.Data
type Provider1 = JsonProvider<""" { "name":"John" } """>
type Provider2 = JsonProvider<""" { "name":"John", "age":94 } """>
let parse parseFn json =
parseFn json
let p1 = parse Provider1.Parse """{ "name": "Not John" }"""
let p2 = parse Provider2.Parse """{ "name": "Not John either", "age": 12 }"""
如果您需要提供类型的多种方法,可以使用例如包含所有必要数据的记录:
type Parser<'b> = {
Parse : string -> 'b
GetSample : unit -> 'b
}
let parseUsing parser text =
printfn "Parsing things like %A" <| parser.GetSample()
parser.Parse text
let parser1 = { Parse = Provider1.Parse; GetSample = Provider1.GetSample }
let parser2 = { Parse = Provider2.Parse; GetSample = Provider2.GetSample }
let p1' = parseUsing parser1 """{ "name": "Not John" }"""
let p2' = parseUsing parser2 """{ "name": "Not John either", "age": 12 }"""
虽然SRTP功能强大(而且很酷),但它们的使用应该受到限制。过度使用会降低编译器的速度,使代码更难理解。