泛用于 UserState 类型的 FParsec 解析器

jcc333

所以。我有一组解析器,我希望它们对用户状态保持通用,因为他们现在不需要这些信息。默认值似乎是 a Parser<'a, obj>,这是不具体的,但我想基本上没问题。但是,在测试中,我希望能够使用CharParsers.run,它需要一个Parser<'a, unit>. 我如何创建一个解析器树,所有这些解析器都共享UserStateFParsec 中类型的通用性,理想情况下不使每个函数都是 type <'a> |= unit -> Parser<SomeType, 'a>,但如果这是我需要做的,那么这就是我需要做的。

FParsec 的CharParsers.run函数只是调用CharParsers.runParserOnStringwith()作为用户状态和""流名称的简写因此,在定义解析器时不要指定您的用户状态,让 F# 的类型推断为您计算它。然后CharParsers.run根据您的需要用于您的测试,F# 将自动推断您的用户状态类型是unit. 然后,一旦您需要引入一些实际的用户状态,只需切换到使用CharParsers.runParserOnString并将其传递给您的初始状态即可。

也许一个例子会有所帮助。假设您需要解析由空格分隔并用括号括起来的整数列表。所以你写你的基本解析器代码:

let pListContents = many (pint32 .>> spaces)
let pList = pchar '[' >>. spaces >>. pListContents .>> pchar ']'

let test p str =
    match run p str with
    | Success(result, _, _)   -> printfn "Success: %A" result
    | Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg

test pList "[1 2 3]"

现在你工作了一段时间,向你的解析器添加特性,最终你发现你想要保留一些用户状态。也许你想存储迄今为止找到的最大数字,或者最长的列表,或者其他东西。所以你改变你的解析器以使用用户状态(我不会给出一个详细的例子,因为听起来你已经知道如何在解析器中使用用户状态),现在你的test函数不再编译,因为它期望用户状态是键入unit(和你做了它intint list什么的)。没问题; 只需test按如下方式更改您的功能:

let test p initState str =
    match runParserOnString p initState "" str with
    // ... the rest of the test function remains unchanged ...

test pList [] "[1 2 3]"

这应该就是你所要做的。只是不要指定解析器函数的类型,让 F# 的类型推断为您完成所有工作,您应该没问题。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章