Разбор типа стрелки с помощью FParsec - PullRequest
0 голосов
/ 06 декабря 2018

Я пытаюсь разобрать тип стрелки с помощью FParsec.То есть это:

Int -> Int -> Int -> Float -> Char

Например.

Я пробовал с этим кодом, но он работает только для одного типа стрелки (Int -> Int) и не более.Я также хочу избежать скобок, потому что у меня уже есть тип кортежа, который использует их, и я не хочу, чтобы он был слишком тяжелым с точки зрения синтаксиса.

let ws = pspaces >>. many pspaces |>> (fun _ -> ())

let str_ws s = pstring s .>> ws

type Type = ArrowType of Type * Type

let arrowtype' =
    pipe2
        (ws >>. ty')
        (ws >>. str_ws "->" >>. ws >>. ty')
        (fun t1 t2 -> ArrowType(t1, t2))

let arrowtype =
    pipe2
        (ws >>. ty' <|> arrowtype')
        (ws >>. str_ws "->" >>. ws >>. ty' <|> arrowtype')
        (fun t1 t2 -> ArrowType(t1, t2)) <?> "arrow type"

ty' - это просто еще одинтипы, такие как кортеж или идентификатор.

У вас есть решение?

1 Ответ

0 голосов
/ 06 декабря 2018

Прежде чем перейти к синтаксису стрелок, я хочу прокомментировать ваш ws парсер.Использование |>> (fun _ -> ()) немного неэффективно, поскольку FParsec должен создать результирующий объект, а затем сразу же выбросить его.Встроенные парсеры spaces и spaces1, вероятно, лучше подойдут вам, поскольку им не нужно создавать объект результата.

ТеперьЧто касается проблемы, с которой вы боретесь, мне кажется, что вы хотите рассмотреть анализатор стрелок немного по-другому.Как насчет того, чтобы рассматривать его как серию типов, разделенных ->, и использовать семейство sepBy комбинаторов синтаксического анализа?Примерно так:

let arrow = spaces1 >>. pstring "->" .>> spaces1
let arrowlist = sepBy1 ty' arrow
let arrowtype = arrowlist |>> (fun types ->
    types |> List.reduce (fun ty1 ty2 -> ArrowType(ty1, ty2))

Обратите внимание, что синтаксический анализатор arrowlist будет также совпадать с простым Int, поскольку определение sepBy1 не "должно быть вхотя бы один разделитель списка ", а точнее" в списке должен быть хотя бы один элемент ".Таким образом, чтобы различать тип Int и тип стрелки, вам нужно сделать что-то вроде:

let typeAlone = ty' .>> notFollowedBy arrow
let typeOrArrow = attempt typeAlone <|> arrowtype

Здесь необходимо использовать attempt, чтобы символы, используемые ty' будет возвращен, если присутствует стрелка.

Есть усложняющий фактор, который я вообще не учел, так как вы упомянули, что не хотите скобок.Но если вы решите, что хотите иметь типы стрелок с типами стрелок (то есть функции, которые принимают функции в качестве входных данных), вы захотите проанализировать такие типы, как (Int -> Int) -> (Int -> Float) -> Char.Это усложнит использование sepBy, и я вообще не обращался к нему.Если вам понадобится более сложный анализ, включая скобки, возможно, вы захотите использовать OperatorPrecedenceParser.Но для ваших простых нужд, где скобки не используются, sepBy1 выглядит как ваша лучшая ставка.

Наконец, я должен дать WARNING : я вообще не проверял это,просто набрал это в поле Stack Overflow.Пример кода, который я дал вам, предназначен не для того, чтобы работать как есть, а для того, чтобы дать вам представление о том, как действовать дальше.Если вам нужен пример «как есть», я с радостью постараюсь вам его дать, но сейчас у меня нет времени на это.

...