F#:高级使用活动模式

时间:2014-05-13 10:40:32

标签: f# pattern-matching

这是我的问题:我正在尝试编写一个利用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

我对此代码的问题是每个新匹配的构造都是嵌套的,这是不可读的,特别是如果你有一长串的结果要匹配。我希望能够定义匹配的运算符,例如:: operator for list,这将使我能够执行以下操作:

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 个答案:

答案 0 :(得分: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可以改变“标记”并返回它,如果不需要更改则返回它,否则返回一个新实例。

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