我试图用FParsec解析箭头类型。也就是说,这个:
Int -> Int -> Int -> Float -> Char例如。
我试过这段代码,但它只适用于一种类型的箭头(Int -> Int),而不再起作用。我还想避免括号,因为我已经有一个元组类型使用它们,而且我也不希望它在语法上太重。
let ws = pspaces >>. many pspaces |>> (fun _ -> ())
let str_ws s = pstring s .>> ws
type Type = ArrowType of Type * Type
let arrowtype' =
pipe2
(ws >>. ty')
(ws >>. str_ws "->" >>. ws >>. ty')
(fun t1 t2 -> ArrowType(t1, t2))
let arrowtype =
pipe2
(ws >>. ty' <|> arrowtype')
(ws >>. str_ws "->" >>. ws >>. ty' <|> arrowtype')
(fun t1 t2 -> ArrowType(t1, t2)) <?> "arrow type"ty'只是另一种类型,如元组或标识符。
你有解决办法吗?
发布于 2018-12-06 17:34:26
在进入箭头语法之前,我想对您的ws解析器进行注释。使用|>> (fun _ -> ())有点效率低下,因为FParsec必须构造一个结果对象,然后立即丢弃它。内置的spaces和spaces1解析器可能更适合您的需要,因为它们不需要构造结果对象。
现在,关于您正在努力解决的问题,在我看来,您想要稍微不同地考虑箭头解析器。如何将其视为由->分隔的一系列类型,并使用解析器组合子的sepBy系列?就像这样:
let arrow = spaces1 >>. pstring "->" .>> spaces1
let arrowlist = sepBy1 ty' arrow
let arrowtype = arrowlist |>> (fun types ->
types |> List.reduce (fun ty1 ty2 -> ArrowType(ty1, ty2))注意,arrowlist解析器还将与普通的Int匹配,因为sepBy1的定义不是“必须至少有一个列表分隔符”,而是“列表中必须至少有一个项”。因此,要区分Int类型和箭头类型,需要执行如下操作:
let typeAlone = ty' .>> notFollowedBy arrow
let typeOrArrow = attempt typeAlone <|> arrowtype在这里,使用attempt是必要的,这样,如果存在箭头,ty'所使用的字符就会被回溯。
有一个复杂的因素,我从来没有提到过,因为你提到不需要括号。但是,如果您想要能够有箭头类型的箭头类型(即接受函数作为输入的函数),那么就需要解析类似于(Int -> Int) -> (Int -> Float) -> Char的类型。这将使sepBy的使用复杂化,而我根本没有解决这个问题。如果您最终需要更复杂的解析(包括括号),那么您可能需要使用OperatorPrecedenceParser。但是对于不涉及括号的简单需求,sepBy1看起来是最好的选择。
最后,我应该给出一个警告:我根本没有测试过它,只是把它输入到堆栈溢出框中。我给您的代码示例并不打算按原样工作,而是想让您了解如何继续工作。如果你需要一个工作的例子,我会很乐意给你一个,但我现在没有时间这样做。
https://stackoverflow.com/questions/53655643
复制相似问题