UserState 类型通用的 FParsec 解析器
FParsec parsers generic to UserState type
所以。我有一组解析器,我希望它们对用户状态保持通用,因为它们现在不需要这些信息。默认值似乎是 Parser<'a, obj>
,这是不明确的,但我想基本上没问题。
但是,在测试中,我希望能够使用 CharParsers.run
,它需要 Parser<'a, unit>
。
我如何创建一个解析器树,所有这些解析器都在 FParsec 中的 UserState
类型上共享通用性,理想情况下不使每个解析器都成为 <'a> |= unit -> Parser<SomeType, 'a>
类型的函数,但如果这是我需要做的,那就是我需要做。
FParsec 的 CharParsers.run
function is just shorthand for calling 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
函数不再编译,因为它期待用户状态为 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# 的类型推断为您完成所有工作,您应该没问题。
所以。我有一组解析器,我希望它们对用户状态保持通用,因为它们现在不需要这些信息。默认值似乎是 Parser<'a, obj>
,这是不明确的,但我想基本上没问题。
但是,在测试中,我希望能够使用 CharParsers.run
,它需要 Parser<'a, unit>
。
我如何创建一个解析器树,所有这些解析器都在 FParsec 中的 UserState
类型上共享通用性,理想情况下不使每个解析器都成为 <'a> |= unit -> Parser<SomeType, 'a>
类型的函数,但如果这是我需要做的,那就是我需要做。
FParsec 的 CharParsers.run
function is just shorthand for calling 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
函数不再编译,因为它期待用户状态为 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# 的类型推断为您完成所有工作,您应该没问题。