使用FParsec解析箭头类型 [英] Parsing the arrow type with FParsec

查看:114
本文介绍了使用FParsec解析箭头类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用FParsec解析箭头类型. 也就是说,这个:

I'm trying to parse the arrow type with FParsec. That is, this:

Int -> Int -> Int -> Float -> Char

例如.

我尝试使用此代码,但它仅适用于一种类型的箭头(Int -> Int),而不再适用.我还想避免使用括号,因为我已经有一个使用它们的元组类型,并且我也不希望它在语法方面过于繁琐.

I tried with this code, but it only works for one type of arrow (Int -> Int) and no more. I also want to avoid parentheses, because I already have a tuple type that uses them, and I don't want it to be too heavy in terms of syntax either.

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'只是另一种类型,例如元组或标识符.

ty' is just another types, like tuple or identifier.

您有解决方案吗?

推荐答案

在介绍箭头语法之前,我想对您的ws解析器进行评论.使用|>> (fun _ -> ())效率不高,因为FParsec必须构造一个结果对象然后立即将其丢弃.内置的 spaces spaces1 解析器可能更适合您的需求,因为它们没有需要构造一个结果对象.

Before I get into the arrow syntax, I want to comment on your ws parser. Using |>> (fun _ -> ()) is a little inefficient since FParsec has to construct a result object then immediately throw it away. The built-in spaces and spaces1 parsers are probably better for your needs, since they don't need to construct a result object.

现在,对于您所苦苦挣扎的问题,在我看来,您似乎希望略微不同地考虑箭头解析器.如何将其视为由->分隔的一系列类型,并使用

Now as for the issue you're struggling with, it looks to me like you want to consider the arrow parser slightly differently. What about treating it as a series of types separated by ->, and using the sepBy family of parser combinators? Something like this:

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类型和箭头类型,您需要执行以下操作:

Note that the arrowlist parser would also match against just plain Int, because the definition of sepBy1 is not "there must be at least one list separator", but rather "there must be at least one item in the list". So to distinguish between a type of Int and an arrow type, you'd want to do something like:

let typeAlone = ty' .>> notFollowedBy arrow
let typeOrArrow = attempt typeAlone <|> arrowtype

在这里必须使用attempt,这样如果出现箭头,ty'消耗的字符将被回溯.

The use of attempt is necessary here so that the characters consumed by ty' will be backtracked if an arrow was present.

有一个复杂的因素我没有解决,因为您提到了不要括号.但是,如果您决定要具有箭头类型的箭头类型(即以函数作为输入的函数),则需要解析(Int -> Int) -> (Int -> Float) -> Char之类的类型.这会使sepBy的使用复杂化,而我根本没有解决.如果最终需要包括括号在内的更复杂的分析,则可能需要使用> c16> .但是对于您不需要括号的简单需求,sepBy1看起来是您的最佳选择.

There's a complicating factor I haven't addressed at all since you mentioned not wanting parentheses. But if you decide that you want to be able to have arrow types of arrow types (that is, functions that take functions as input), you'd want to parse types like (Int -> Int) -> (Int -> Float) -> Char. This would complicate the use of sepBy, and I haven't addressed it at all. If you end up needing more complex parsing including parentheses, then it's possible you might want to use OperatorPrecedenceParser. But for your simple needs where parentheses aren't involved, sepBy1 looks like your best bet.

最后,我应该给出一个警告:我根本没有测试过,只需在堆栈溢出"框中键入此内容即可.我给您的代码示例并非旨在按原样工作,而是为您提供了如何进行操作的想法.如果您需要一个按原样工作的示例,我很乐意尝试给您一个示例,但是我现在没有时间这样做.

Finally, I should give a WARNING: I haven't tested this at all, just typed this into the Stack Overflow box. The code example I gave you is not intended to be working as-is, but rather to give you an idea of how to proceed. If you need a working-as-is example, I'll be happy to try to give you one, but I don't have the time to do so right now.

这篇关于使用FParsec解析箭头类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆