Reputation: 652
I have two JsonProvider types:
type Provider1 = JsonProvider<"""{structure}""">
type Provider2 = JsonProvider<"""{}structure2""">
I'd like to have a function, that can accept any of these and parse json using provided JsonProvider, something like this:(pseudo code, not compiling)
let parseUsingSpecificProvider json (provider : JsonProvider<GENERIC>) =
provider.Parse json
Upvotes: 1
Views: 382
Reputation: 8551
In functional programming it is common to replace 'single function interfaces' with the function itself. I.e. instead of passing in a parser having a Parse
method, just use the Parse
function as a first class value:
#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 }"""
If you need several methods of the provided type, you could use e.g. a record containing all necessary data:
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 }"""
While SRTPs are powerful (and cool), their usage should be limited. Overuse slows down the compiler and makes code harder to understand.
Upvotes: 0
Reputation: 26204
You can define an inline function with Statically Resolved Type Parameters (SRTPs):
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>
So it will work with any type that has the static method Parse
accepting a string as input.
Upvotes: 2