你做了一项出色的研究,几乎回答了自己的问题。
通常有两种方法:
-
无条件地
解析出
int
并让进一步的代码检查其有效性;
-
使用
警戒规则
绑定到解析器。在这种情况下
(>>=)
是正确的工具;
为了做出一个好的选择,问问自己
失败
要通过警戒规则,必须通过触发“再给一次机会”
另一个解析器
?
这就是我的意思。通常,在现实生活中的项目中,解析器被组合在一些链中。如果一个解析器失败,则尝试执行下一个解析器。例如,在
this question
,某些编程语言被解析,因此它需要以下内容:
let pContent =
pLineComment <|> pOperator <|> pNumeral <|> pKeyword <|> pIdentifier
理论上,DSL可能需要将“小int值”与其他类型区分开来:
/// The resulting type, or DSL
type Output =
| SmallValue of int
| LargeValueAndString of int * string
| Comment of string
let pSmallValue =
pint32 >>= (fun x -> if x <= 1048576 then (preturn x) else fail "int parsed larger than maxRows")
|>> SmallValue
let pLargeValueAndString =
pint32 .>> ws .>>. (manyTill ws)
|>> LargeValueAndString
let pComment =
manyTill ws
|>> Comment
let pCombined =
[ pSmallValue; pLargeValueAndString; pComment]
|> List.map attempt // each parser is optional
|> choice // on each iteration, one of the parsers must succeed
|> many // a loop
以这种方式构建,
pCombined
将返回:
-
"42 ABC"
获取解析为
[ SmallValue 42 ; Comment "ABC" ]
-
"1234567 ABC"
获取解析为
[ LargeValueAndString(1234567, "ABC") ]
正如我们所看到的,保护规则影响解析器的应用方式,因此保护规则必须在解析过程中。
然而,如果您不需要这种复杂性(例如
整数
已解析
无条件地
),您的第一段代码很好。