Распаковка вложенных аппликативных функторов f # - PullRequest
2 голосов
/ 19 марта 2019

Привет. Я пытаюсь создать парсер комбинатора, и сейчас я пытаюсь заставить его читать заголовки и создавать парсеры, основываясь на том, что это за анализируемый заголовок.Т.е. заголовок;int, float, string приведут к Parser<Parser<int>*Parser<float>*Parser<string>>.

Мне интересно, однако, как бы вы распаковали «внутренние» парсеры, которые затем получат нечто подобное;Parser<int*float*string>?

Тип парсера: type Parser<'a> = Parser of (string -> Result<'a * string, string>)

1 Ответ

1 голос
/ 19 марта 2019

Я не уверен, что ваша идея с вложенными парсерами сработает - если вы анализируете заголовок динамически, то вам нужно будет создать список парсеров того же типа. То, как вы это написали, предполагает, что тип парсера будет зависеть от ввода, что невозможно в F #.

Итак, я ожидаю, что вам нужно будет определить значение следующим образом:

type Value = Int of int | String of string | Float of float

И тогда ваш парсер, который разбирает заголовок, выдаст что-то вроде:

let parseHeaders args : Parser<Parser<Value> list> = (...)

Следующий вопрос: что вы хотите делать с вложенными парсерами? Предположительно, вам нужно превратить их в один анализатор, который анализирует всю строку данных (если это что-то вроде CSV-файла). Обычно вы определяете функцию sequence:

val sequence : sep:Parser<unit> -> parsers:Parser<'a> list -> Parser<'a list>

Это берет разделитель (скажем, парсер для распознавания запятой) и список парсеров и создает один парсер, который запускает все парсеры в последовательности с разделителем между ними.

Тогда вы можете сделать:

parseHeaders input |> map (fun parsers -> sequence (char ',') parsers)

И вы получите один парсер Parser<Parser<string>>. Теперь вы хотите запустить вложенный анализатор на оставшейся части, которая остается после запуска внешнего анализатора, который распознает заголовки. Следующая функция делает трюк:

let unwrap (Parser f:Parser<Parser<'a>>) = Parser (fun s ->
  match f s with
  | Result.Ok(Parser nested, rest) -> nested rest 
  | Result.Error e -> Result.Error e )
...