Reputation: 3292
So, I can easily write an arbitrary type to JSON
with Newtonsoft.Json
:
type X = {
Number: decimal
Sequence: decimal
NumList: decimal list
}
let createItem (n, s, nL) =
{Number = n;
Sequence = s;
NumList = nL}
let items =
[
(1M, 1M, [1M; 2M; 3M])
(2M, 2M, [2M; 4M; 6M])
(3M, 3M, [3M; 6M; 9M])
]
|> List.map createItem
open Newtonsoft.Json
open System.IO
let writeToJson (path: string) (obj: 'a) : unit =
let serialized = JsonConvert.SerializeObject(obj)
File.WriteAllText(path, serialized)
writeToJson "xList.json" items
How can I write a function generic enough that I can read a JSON
file? In other words, I'd like something like:
let readFromJson (path: string) (t: 'T) =
let convertToQr = File.ReadAllText(path)
Newtonsoft.Json.JsonConvert.DeserializeObject<t list>(convertToQr)
where the second argument is the Type
of the object in path
, but I don't know how to do that. If I try to use this function as is, I get a compiler error.
How can I declare in the second argument above the type of the thing that is in path
? Can I?
Upvotes: 1
Views: 380
Reputation: 80744
Generic parameters, when explicitly defined, are written in angle brackets immediately after function name, before regular parameters:
let readFromJson<'T>(path: string) =
let convertToQr = File.ReadAllText(path)
Newtonsoft.Json.JsonConvert.DeserializeObject<'T list>(convertToQr)
Usage:
readFromJson<string> "/some/file.json"
Alternatively, you can specify the return type of your function, and let the compiler infer all generic parameters and arguments for you:
let readFromJson(path: string) : 't list =
let convertToQr = File.ReadAllText(path)
Newtonsoft.Json.JsonConvert.DeserializeObject(convertToQr)
Here, the compiler knows that the generic argument of DeserializeObject
must be 't list
, because its result is being returned from readFromJson
, and the result type of readFromJson
is explicitly declared to be 't list
. Similarly, just by noticing a generic type in the function definition, the compiler will infer that the function has one generic parameter.
In a similar way, you can let the compiler infer the required type when you call the function:
// call inferred to readFromJson<string>, because that's the required return type
let s: string list = readFromJson "/some/file.json"
Upvotes: 6