为什么我不能把这个字符串变成文字?

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

我需要将字符串转换为文字,以便将其作为参数传递给 CsvProvider。但我做不到。下面的代码运行没有问题:

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

但是,当添加下面两行时

[<Literal>]
let tradedPath = trp

最后我收到消息 This is not a valid constant expression or custom attribute value

我什至尝试制作 trp 的副本,但这没有帮助。

有什么办法可以避免这个问题?

遗憾的是,您无法通过向普通值应用 [<Literal>] 属性将它神奇地变成文字值。

文字值的特殊之处在于它被编译为常量,这意味着它们必须在编译时可确定。

例如,这是一个文字字符串:

[<Literal>]
let testLiteral = "This is a literal string"

您可以将多个文字字符串组合成一个新的文字字符串:

[<Literal>]
let a = "a"
[<Literal>]
let b = "b"
[<Literal>]
let ab = a + b

您不能将任意函数应用于文字,因为那样它们将无法在编译时确定。

More about literals.

查看您上次尝试使用 CsvProvider 的评论,您当然可以使用其他方法来解析 csv 文件,但也可以在 __SOURCE_DIRECTORY__ 以及向提供者提供 ResolutionFolder 参数(尽管这必须是文字)。这里有两个示例,一个使用项目根目录中的示例来创建类型,然后使用实际文件的命令行参数。另一个使用相对路径来解析文件。

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

对于输出: