F#: 高级使用主动模式

7

以下是我的问题:我正在尝试编写一个解析器,利用F#中的主动模式。解析函数的基本签名如下:

LazyList<Token> -> 'a * LazyList<Token>

意味着它需要一个惰性令牌列表,并返回解析的结果和解析后的新令牌列表,以遵循函数式设计。现在,作为下一步,我可以定义活动模式,以帮助我直接匹配某些结构在匹配表达式中。
let inline (|QualName|_|) token_stream =
    match parse_qualified_name token_stream with
        | Some id_list, new_stream -> Some (id_list, new_stream)
        | None, new_stream -> None

let inline (|Tok|_|) token_stream = 
    match token_stream with
        | Cons (token, tail) -> Some(token.variant, tail)
        | _ -> None

然后以高层次的方式匹配解析结果。
let parse_subprogram_profile  = function
    | Tok (Kw (KwProcedure | KwFunction),
           QualName(qual_name, 
                    Tok (Punc (OpeningPar), stream_tail))) as token_stream ->
        // some code
    | token_stream -> None, token_stream

我对这段代码的问题在于每个新匹配的构造都是嵌套的,这样不太易读,特别是当你有很多结果需要匹配时。我希望能够定义一个匹配运算符,比如列表的::运算符,这将使我能够做到以下操作:

let parse_subprogram_profile  = function
    | Tok (Kw (KwProcedure | KwFunction)) :: 
      QualName(qual_name) :: 
      Tok (Punc (OpeningPar)) :: stream_tail as token_stream ->
        // some code
    | token_stream -> None, token_stream

但我认为在F#中这是不可能的。我甚至可以接受一个设计,其中我必须调用特定的“ChainN”活动模式,其中N是我想解析的元素数量,但如果可能的话,我不知道如何设计这样的函数。
关于此事,有什么建议或方向吗?是否存在一种明显的设计我没有看到的?
1个回答

3

我也曾经考虑过类似的设计,但最终放弃了。你可以尝试使用实际的列表。

在这种情况下,你可以创建一个 CombinedList,它由两个部分组成:(首先)一个普通的列表作为缓冲区和(其次)一个惰性列表。

当你想匹配一个模式时,可以这样操作:

match tokens.EnsureBuffer(4) with
| el1 :: el2 :: remaining               -> (el1.v+el2.v, tokens.SetBuffer(remaining))
| el3 :: el4 :: el5 :: el6 :: remaining -> (el1.v-el2.v+el3.v-el4.v, tokens.SetBuffer(remaining))

EnsureBuffer和SetBuffer可能会改变“tokens”并返回它,或者如果不需要更改,则直接返回它,否则返回新实例。

这样能解决您的问题吗? 弗朗索瓦


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接