Reputation: 810
I am trying to use the CsvProvider from FSharp.Data following the example here: http://fsharp.github.io/FSharp.Data/library/CsvProvider.html
In the example they define a type and then use the type but it looks like they are doing it in interactive mode. I am trying to do the same thing in my main but I don't understand why it doesn't work.
In the eample they do the following:
type Stocks = CsvProvider<"../data/MSFT.csv">
This is my attempt:
open System
open System.IO
open FSharp.Data
// Process execution params
// args(0) = nesting level
// args(1) = csv file name
[<EntryPoint>]
let main (args: string[]) =
printfn "Arguments passes in: %A" args
// F# searches the following directory at runtime : C:\Users\userName\source\repos\crawlerF\crawlerF\bin\Debug\netcoreapp2.1\test.csv'.
// It is therefore necessary to provide the top level of the repo for the file read by prepending ../../../../ to the file name
let filePath = "../../../../" + args.[1]
type urls = CsvProvider<filePath>
0
I get a few syntax errors when I try to define the urls variable. Why is this the case? I am new to F# so a more novice explanation would be appreciated.
Thanks.
Upvotes: 1
Views: 838
Reputation: 1286
There are a few things going on here:
You can't define types within a function, so you need to move the definition of urls
out of the main
function and into a module or namespace.
Type providers give you an easy way to generate types rather than defining them yourself manually, but these types still need to be generated at compile-time. This means that any parameter you pass to a type provider must be static, i.e. must have a value at compile-time.
In your case, the filePath
of your sample CSV file is the only parameter you're passing to the CsvProvider
, but because this value is derived from a command line argument it is only known at runtime. To pass a static file name to the CsvProvider
you can use a literal string, e.g.
// Option 1: Use an inline literal string, like in the example from FSharp.Data.
type Urls = CsvProvider<"test.csv">
// Option 2: Use a named literal so that the compiler knows this value is static.
let [<Literal>] FilePath = "test.csv"
type Urls = CsvProvider<FilePath>
This may just be a formatting error in your code sample, but in order to return the 0
from your main
function, it must be indented so that it's recognised as the last expression of that code block.
Putting this all together gives you something like the following:
open FSharp.Data
module Program =
// The `Urls` type is now defined within a module.
// This type is generated at compile-time from the sample file.
// Assumes the sample file 'test.csv' exists in the project folder at compile-time.
type Urls = CsvProvider<"test.csv">
[<EntryPoint>]
let main args =
// Use the generated `Urls` type to load some data at runtime.
let urls = Urls.Load("...")
// ...
// Return an integer exit code.
0
Upvotes: 3