FParsec и pipe3 делают аргументы явными или добавляют обозначение типа - PullRequest
0 голосов
/ 05 февраля 2019

Я пытаюсь использовать функцию pipe3 из библиотеки FParsec, но получаю ошибку, не знаю, как ее решить.

Учитывая запись

type Point = { x: float; y: float }

и следующий синтаксический анализатор

let plistoffloats' =
    pipe3 pfloat (pchar ',' .>> spaces) pfloat 
        (fun first z second -> { x = first; y = second })

Я пытаюсь добиться парсера, который получает строку в формате "1.1, 3.7" и возвращает Point

run plistoffloats' "1.1, 3.7"

Input: "1.1, 3.7"

Требуемый выход : Point = {x = 1.1; y = 3.7;}

Ошибка :

ошибка FS0030: ограничение значения.Значение 'plistoffloats' 'было выведено, чтобы иметь универсальный тип val plistoffloats': Parser <Point,'__a>
Либо сделайте аргументы для 'plistoffloats' явными, либо, если вы не собираетесь использовать его как универсальный, добавьте аннотацию типа.

Более простой пример с pchar также не работает.

let parsesA = pchar 'a'

Ошибка FS0030: ограничение значения.Значение 'parsesA' было выведено для того, чтобы иметь универсальный тип val parsesA: Parser<char,'_a> Либо сделать аргументы для 'parsesA' явными, либо, если вы не собираетесь использовать его как универсальный, добавьте аннотацию типа.

1 Ответ

0 голосов
/ 05 февраля 2019

Это описано в документации FParsec ;это случится с любым парсером.Причина в том, что в системе типов .Net функции могут быть общими, а значения - нет, а в FParsec вы обычно определяете синтаксические анализаторы как значения (например,вы обычно пишете let psomething = ..., где psomething не принимает параметров).Прочитайте страницу с соответствующей документацией для полного объяснения - я не буду копировать и вставлять все это - но короткая версия заключается в том, что вы можете сделать одну из двух вещей:

  1. Создать test функция, которая выглядит следующим образом: и убедитесь, что она используется в том же исходном файле в вашем анализаторе :

    let test p str =
        match run p str with
        | Success(result, _, _)   -> printfn "Success: %A" result
        | Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg
    
  2. Добавьте в свой анализатор типаннотация, подобная следующей:

    type UserState = unit   // You might change this later
    let plistoffloats' : Parser<_, UserState> =
        // ...
    

Звучит так, как будто вы пытаетесь сделать # 1, но если ваш парсер не вызывается с test plistoffloats' в том же исходном файле, F #вывод типа не сможет вывести ваш тип состояния пользователя и выдаст эту ошибку.

PS Подробнее об ошибке ограничения значения F # можно прочитать здесь: Понимание ошибок ограничения значения F #

PPS _ в первой позиции Parser<_, UserState> не означает «Этот тип может быть чем-либо», как _ в других контекстах, таких как сопоставление с образцом.Вместо этого _ в аннотации типа означает «Пожалуйста, укажите этот тип для меня, чтобы мне не приходилось указывать его явно».В контексте FParsec это очень полезно, потому что все ваши парсеры будут иметь UserState в качестве аргумента second типа, но будут иметь переменный тип для аргумента типа first .И поскольку аргумент типа first является тем, который может выводить вывод типа, это означает, что вы можете скопировать и вставить тип Parser<_, UserState> во все ваши синтаксические анализаторы, и F # будет делать правильные вещи ™ в каждом случае.

...