FParsec解析器通用于UserState类型

时间:2018-02-20 03:08:08

标签: f# fparsec

因此。我有一套解析器,我希望保持通用的用户状态,因为他们现在不需要这些信息。默认值似乎是Parser<'a, obj>,这是非特定的,但我认为很好。 但是,在测试中,我希望能够使用期望CharParsers.run的{​​{1}}。 我如何创建一个解析器树,所有解析器都在FParsec中的Parser<'a, unit>类型上共享通用性,理想情况下不会使每个类型都成为UserState类型的函数,但如果这是我需要做的事情那就是我需要做的事情。

1 个答案:

答案 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类型(并且您已将其设为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#的类型推断为你完成所有的工作,你应该没问题。