Reputation: 121
I have found this superb JSON library for F#, it's inspired by Elm's Json.Decode and it defines a basic Decoder
type like this:
type Decoder<'T> = string -> obj -> Result<'T, DecoderError>
(here)
There are functions like Decode.map and I wish I could make it F#+ compatible, so I could use it like:
let customerId = Decode.string |>> CustomerId
(see |>> infix version of generic map)
As far as I can see, to make a 3rd party library use F#+ concepts like Functors, one needs to extend the 3rd party type with static member Map
, but the Decoder<'T>
is just an abbreviation.
Is there any solution? Did anyone try?
P.S. My solution so far is a custom binding:
let (<!>) = Decode.map
let customerId: Decoder<CustomerId> = CustomerId <!> Decode.string
let submitId: Decoder<SubmitId> = SubmitId <!> Decode.string
let currency: Decoder<Currency> = Currency <!> Decode.string
// etc…
Upvotes: 2
Views: 275
Reputation: 26174
The problem is that you don't control the code. If you had control over it, a solution would be:
Implement Decoder
as a concrete type as opposed to a type alias. A type alias can't have additional members, because it's not really another type. Library authors should use single case discriminated unions, now that you can make them structs with nearly zero overhead.
Add the member Map
with the required signature.
Alternatively, if extensions members becomes visible for trait constraints in a future F# version, you would be able just extend the type with the Map function, maybe with some undesired effects as it's a type alias for a function with 2 arguments.
So, I think the best you can do is what you already showed.
As a side note, you might be interested in having a look at Fleece which also provides decoders, but it also goes one step further and provides you codecs which goes in both directions (and you can map
and <*>
over it).
Upvotes: 3