Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I turn this string into a Literal?

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?

like image 929
Soldalma Avatar asked Mar 02 '17 19:03

Soldalma


People also ask

Why can't you make a reference to a literal?

It isn't correct because the string literal is not a pointer. It is an array. The literal does implicitly convert to a pointer to the first element of the array (just like all arrays do), but that result of the conversion is an rvalue. And an lvalue reference to non-const cannot be bound to an rvalue.

How do you convert a string to a literal in Python?

In Python, when you prefix a string with the letter r or R such as r'...' and R'...' , that string becomes a raw string. Unlike a regular string, a raw string treats the backslashes ( \ ) as literal characters.

Which is the string literal?

A "string literal" is a sequence of characters from the source character set enclosed in double quotation marks (" "). String literals are used to represent a sequence of characters which, taken together, form a null-terminated string. You must always prefix wide-string literals with the letter L.


2 Answers

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.

More about literals.

like image 184
TheInnerLight Avatar answered Oct 01 '22 00:10

TheInnerLight


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:

enter image description here

like image 37
s952163 Avatar answered Oct 01 '22 00:10

s952163