打开嵌套的应用函子f#的包装

时间:2019-03-18 21:06:11

标签: parsing parser-combinators

嗨,我正在尝试制作一个组合器解析器,并且当前正在尝试使其读取标头并根据所解析的标头创建解析器。即标题; 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 个答案:

答案 0 :(得分:1)

我不确定您使用嵌套解析器的想法是否行得通-如果您动态解析标头,则需要生成相同类型的解析器列表。您编写此代码的方式表明,解析器的类型将取决于输入,这在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 )