嗨,我正在尝试制作一个组合器解析器,并且当前正在尝试使其读取标头并根据所解析的标头创建解析器。即标题; int,float,string将产生Parser<Parser<int>*Parser<float>*Parser<string>>
。
但是我想知道您将如何解压缩“内部”解析器,然后最终得到类似的东西; Parser<int*float*string>?
解析器类型为:type Parser<'a> = Parser of (string -> Result<'a * string, string>)
答案 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 )