Reputation: 4758
I need to convert a string into a Literal so I can pass it as an argument to CsvProvider. But I am not able to do it. The code below runs with no problems:
open System.IO
open FSharp.Data
open FSharp.Data.JsonExtensions
let charSwitch (a: char) b x =
if x = a then
b
else
x
let jsonDataPath = Path.Combine(__SOURCE_DIRECTORY__, @"data\fractal.json")
let jsonData = JsonValue.Load(jsonDataPath)
/// Path with traded assets
let trp = ((jsonData?paths?tradedAssets).AsString() |> Core.String.map (charSwitch '\\' '/')).ToString()
printfn "trp is a standard string: %s" trp
// trp is a standard string: H:/Dropbox/Excel/Data/Fractal/Traded.csv
However, when add the following two lines
[<Literal>]
let tradedPath = trp
at the end I get the message This is not a valid constant expression or custom attribute value
.
I even tried to make a copy of trp but that did not help.
Any way to circumvent this problem?
Upvotes: 5
Views: 648
Reputation: 6324
Looking at your last comment you're trying to use the CsvProvider
, you can of course use something else to parse the csv file, but it's also possible to use [<Litera>]
on the __SOURCE_DIRECTORY__
as well as give a ResolutionFolder argument (this has to be a Literal though) to the provider. Here are two examples, one uses a sample in the Project root to create the type but then uses a command line argument for the actual file. The other one uses relative path to parse the file.
open System
open FSharp.Data
open FSharp.Data.JsonExtensions
#if INTERACTIVE
#r @"..\packages\FSharp.Data.2.3.2\lib\net40\FSharp.Data.dll"
#endif
[<Literal>]
let file = __SOURCE_DIRECTORY__ + @"\file1.csv"
[<Literal>]
let path3 = __SOURCE_DIRECTORY__
[<Literal>]
let path4 = "."
type SampleFile = CsvProvider<file,HasHeaders=true>
type SampleFile3 = CsvProvider<"file1.csv",HasHeaders=true,ResolutionFolder=path3>
[<EntryPoint>]
let main argv =
//let nonLiteralPath = @".\file1.csv" // you could hardcode this in the file but:
let nonLiteralPath = argv.[0] // you can also use a path specified on the command line
let DataFile = SampleFile.Load(nonLiteralPath)
[for row in DataFile.Rows -> row.``Key #1``] |> printfn "%A"
let x= SampleFile3.GetSample() // use a relative path, this will be the root of the project at design time
// or the root of the exe at the execution time
[for row in x.Rows -> row.``Key #2``] |> printfn "%A"
printfn "%A" argv
And for the output:
Upvotes: 3
Reputation: 12184
Sadly, you can't magically turn an ordinary value into a literal value by applying the [<Literal>]
attribute to it.
The special thing about literal values is that are compiled as a constant and that means they have to be determinable at compile time.
For example, this is a literal string:
[<Literal>]
let testLiteral = "This is a literal string"
You can combine several literal strings into a new literal string:
[<Literal>]
let a = "a"
[<Literal>]
let b = "b"
[<Literal>]
let ab = a + b
You cannot apply arbitrary functions to literals because then they would not be determinable at compile time.
Upvotes: 6