Using ParserResult

Below is a sample code below:

open FParsec let capitalized : Parser<unit,unit> =(asciiUpper >>. many asciiLower >>. eof) let inverted : Parser<unit,unit> =(asciiLower >>. many asciiUpper >>. eof) let capsOrInvert =choice [capitalized;inverted] 

Then you can:

 run capsOrInvert "Dog";; run capsOrInvert "dOG";; 

and get success or:

 run capsOrInvert "dog";; 

and get a failure.

Now that I have a ParserResult, how do I do something with it? For example, print the line back?

+5
source share
2 answers

There are several important issues in your code.

First of all, as @scrwtp noted in the answer, your parser returns unit . Here's why: operator (>>.) Returns only the result returned by the correct internal parser. On the other hand, (.>>) will return the result of the left parser, and (.>>.) Will return the tuple of both the left and the right.

So parser1 >>. parser2 >>. eof parser1 >>. parser2 >>. eof parser1 >>. parser2 >>. eof essentially (parser1 >>. parser2) >>. eof (parser1 >>. parser2) >>. eof .
The code in parens completely ignores the result of parser1 , and the second (>>.) Then ignores the entire result of the analyzer in parens. Finally, eof returns unit , and this value is returned.

Instead, you may need some meaningful data returned , for example. parsed string. The easiest way:

 let capitalized = (asciiUpper .>>. many asciiLower .>> eof) 

Pay attention to the operators. The code for inverted can be executed in a similar way.


This parser will be of type Parser<(char * char list), unit> , tuple of the first character and all the rest, so you may need to combine them back . There are several ways to do this:

 let mymerge (c1: char, cs: char list) = c1 :: cs // a simple cons let pCapitalized = capitalized >>= mymerge 

The beauty of this code is that your mymerge is a normal function , working with a regular char , it does not know anything about parsers or so. It just works with data, and the operator (>>=) does the rest.

Note. pCapitalized also a parser, but returns a single char list .


Nothing stops you from applying further transitions . As you mentioned, print the line back:

 let pCapitalizedAndReversed = capitalized >>= mymerge >>= List.rev 

I wrote the code this way for the purpose. On different lines, you see a gradual transition of your domain data, still within the Parser paradigm . This is important because any subsequent transition may "decide" that the data is bad for some reason and, for example, raises a parsing exception. Or, alternatively, it can be combined with another parser.

As soon as the data of your domain (the parsed word) is completed, you will get the result, as indicated in another answer.


A small note. choice is redundant for only two parsers. Use (<|>) instead. From experience, careful selection of parser combinators is important because making the wrong choice inside your parsing logic can easily cause your parsers to slow down dramatically.
See FParsec Primitives for more details.

+7
source

ParserResult is a discriminatory association. You simply compare Success and Failure cases.

 let r = run capsOrInvert "Dog" match r with | Success(result, _, _) -> printfn "Success: %A" result | Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg 

But this is probably not what you consider difficult in your situation.

The thing about your Parser<unit, unit> is that the parsed value is of type unit (the first type argument for Parser ). This means that this parser does not really give any reasonable result for use - it can only tell you if it can parse a string (in this case you return Success ((), _, _) - transferring a single value of type unit ) or no.

What do you expect from this parser?

Change This is similar to what you want, or at least you should remove some pointers. capitalized takes uppercase strings, inverted accepts uppercase strings that were canceled and canceled as part of the parser logic.

 let reverse (s: string) = System.String(Array.rev (Array.ofSeq s)) let capitalized : Parser<string,unit> = (asciiUpper .>>. manyChars asciiLower) |>> fun (upper, lower) -> string upper + lower let inverted : Parser<string,unit> = (manyChars asciiLower .>>. asciiUpper) |>> fun (lower, upper) -> reverse (lower + string upper) let capsOrInvert = choice [capitalized;inverted] run capsOrInvert "Dog" run capsOrInvert "doG" run capsOrInvert "dog" 
+6
source

Source: https://habr.com/ru/post/1259788/


All Articles