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