Reputation: 5503
I am using the CsvTypeProvider to map data from CSV files into my own data structures. This works splendidly, except for that I have to repeat the mapping function every time:
type GamesFile = CsvProvider<"./data/15.csv">
let games15 = GamesFile.Load("./data/15.csv").Rows |> Seq.map ( fun c -> { Division = c.Div; Date = c.Date; HomeScore = c.HomeScore; AwayScore = c.AwayScore })
let games16 = GamesFile.Load("./data/16.csv").Rows |> Seq.map ( fun c -> { Division = c.Div; Date = c.Date; HomeScore = c.HomeScore; AwayScore = c.AwayScore })
When I try moving it to a function, I am told that "Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved."
This makes sense, but how can I tell a mapping function what type it is when the type is inferred from the contents of the CSV? How is this normally solved?
Upvotes: 3
Views: 169
Reputation: 243096
The type provider generates a type representing the row and it exposes it as a nested type of the main provided type - in your case aliased as GamesFile
.
This is not entirely obvious, because the editors will show tooltip with something like
CsvFile<...>.Row
so it does not show the name of the alias, but it suggests Row
is a nested type. To use the type in your code, you can just write GamesFile.Row
, so you need something like this:
type GamesFile = CsvProvider<"./data/15.csv">
let mapRows (rows:seq<GamesFile.Row>) =
rows |> Seq.map (fun c ->
{ Division = c.Div; Date = c.Date; HomeScore = c.HomeScore; AwayScore = c.AwayScore })
let games15 = GamesFile.Load("./data/15.csv").Rows |> mapRows
let games16 = GamesFile.Load("./data/16.csv").Rows |> mapRows
Upvotes: 5