F #: extended use of active templates

Here is my problem: I am trying to write a parser using the power of active templates in F #. The main signature of the parsing function is as follows:

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

The value of this requires a lazy list of tokens and returns the result of the analysis and a new list of tokens after parsing in order to follow the functional design.

Now, as a next step, I can define active patterns that will help me match some constructs directly in expression expressions, this way

 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 

and then match the parsing results in this way to a high level

 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 

The problem with this code is that each new mapped construct is nested, which is impossible to read, especially if you have a long chain of results to match. I would like to be able to define an appropriate operator, such as the :: operator for a list, which would allow me to do the following:

 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 

But I do not think that such a thing is possible in F #. I would even agree with a design in which I need to call a specific active ChainN template, where N is the number of elements that I want to parse, but I don’t know how to create such a function, if possible.

Any tips or guidance on this? Is there an obvious design that I have not seen?

+7
pattern-matching f #
source share
1 answer

I also had something similar, but actually abandoned this exact design. Something you can do is use actual listings.

In this case, you will have a CombinedList, which consists of (firstly) a normal list acting as a buffer, and (secondly) a lazy list.

If you want a pattern match, you can do:

 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)) 

where EnsureBuffer and SetBuffer can either mutate "tokens", or return them or return if changes are not required or return new instances otherwise.

Will this solve your problem? Francois

+3
source share

All Articles