Почему я не могу превратить эту строку в литерал?

Мне нужно преобразовать строку в литерал, чтобы я мог передать ее в качестве аргумента 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, но это не помогло.

Любой способ обойти эту проблему?


person Soldalma    schedule 02.03.2017    source источник
comment
@FoggyFinder — CsvProvider работает, только если аргумент Sample является литералом. Например, type TickerName = CsvProvider<"C:/temp/myfile.csv"> работает нормально, но 'let fil = C:/temp/myfile.csv` вместе с type TickerName = CsvProvider<fil>' does not work. Placing [‹Literal›]` в строке чуть выше 'let fil = C:/temp/myfile.csv` решает проблему. . Но я не могу сделать это со строкой, показанной в моем вопросе, предположительно потому, что она была рассчитана. В SO есть пара вопросов о необходимости поставщиков типов для буквальных аргументов Sample.   -  person Soldalma    schedule 02.03.2017
comment
Вы должны иметь возможность использовать метод Load для вашего типа TickerName для загрузки ресурса из другого источника, который следует той же схеме, что и ваш локальный ресурс ""C:/temp/myfile.csv".   -  person TheInnerLight    schedule 02.03.2017
comment
@TheInnerLight - мне не удалось создать тип TickerName, потому что мне нужно, чтобы traderPath был литералом в type TickerName = CsvProvider<tradedPath>. Не удалось создать тип TickerName, я не могу вызвать его метод Load. Я мог бы создать тип TickerName, жестко закодировав имя файла следующим образом: type TickerName = CsvProvider<"C:/temp/myfile.csv">, но я не хочу этого делать, потому что я хочу, чтобы файл Sample определялся во время выполнения.   -  person Soldalma    schedule 02.03.2017
comment
@Soldalma Нет возможности определить образец во время выполнения. Это не то, как работают поставщики типов. Почему вы не можете сделать type TickerName = CsvProvider<"C:/temp/myfile.csv">, а затем TickerName.Load(trp)?   -  person TheInnerLight    schedule 03.03.2017


Ответы (2)


Глядя на ваш последний комментарий, вы пытаетесь использовать CsvProvider, вы, конечно, можете использовать что-то еще для анализа файла csv, но также возможно использовать [<Litera>] в __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

И для вывода:

введите здесь описание изображения

person s952163    schedule 02.03.2017

К сожалению, вы не можете волшебным образом превратить обычное значение в буквальное значение, применив к нему атрибут [<Literal>].

Особенность литеральных значений заключается в том, что они компилируются как константы, а это означает, что они должны быть определены во время компиляции.

Например, это буквальная строка:

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

Вы можете объединить несколько литеральных строк в новую литеральную строку:

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

Вы не можете применять произвольные функции к литералам, потому что тогда они не будут определяться во время компиляции.

Подробнее о литералах.

person TheInnerLight    schedule 02.03.2017
comment
Справедливо. Но значит ли это, что я не могу определить путь к CSV-файлу, который будет аргументом Sample для CsvProvider во время выполнения? Нет ли альтернативы жесткому кодированию этого пути? - person Soldalma; 02.03.2017
comment
@Soldalma Образец используется для генерации типов, поэтому нет альтернативы знанию его во время компиляции. Ваш рабочий процесс должен заключаться в использовании файла схемы, который может быть разрешен во время компиляции, и присвоении ему разных целей, которые следуют одной и той же схеме с помощью метода Load во время выполнения. - person TheInnerLight; 02.03.2017
comment
@Soldalma, конечно, вы можете использовать атрибут [<Literal>] для самого __SOURCE_DIRECTORY__. Это может быть связано с exe. - person s952163; 03.03.2017