因此。我有一套解析器,我希望保持通用的用户状态,因为他们现在不需要这些信息。默认值似乎是Parser<'a, obj>
,这是非特定的,但我认为很好。
但是,在测试中,我希望能够使用期望CharParsers.run
的{{1}}。
我如何创建一个解析器树,所有解析器都在FParsec中的Parser<'a, unit>
类型上共享通用性,理想情况下不会使每个类型都成为UserState
类型的函数,但如果这是我需要做的事情那就是我需要做的事情。
答案 0 :(得分:0)
FParsec&#39; CharParsers.run
function只是以()
作为用户状态调用CharParsers.runParserOnString
的简写,""
作为流名称。因此,在定义解析器时,不要指定用户状态,并让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
函数不再编译,因为它& #39; s期望用户状态为unit
类型(并且您已将其设为int
或int 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#的类型推断为你完成所有的工作,你应该没问题。