How to convert an FParsec parser to parse whitespace
Asked Answered
C

1

1

I'm implementing a parser that treats comments as white space with FParsec. It seems like it requires a trivial parser conversion, but I don't yet know how to implement that.

Here's the code I'm trying to get to type-check -

let whitespaceTextChars = " \t\r\n"

/// Read whitespace characters.
let whitespaceText = many (anyOf whitespaceTextChars)

/// Read a line comment.
let lineComment = pchar lineCommentChar >>. restOfLine true

/// Skip any white space characters.
let skipWhitespace = skipMany (lineComment <|> whitespaceText)

/// Skip at least one white space character.
let skipWhitespace1 = skipMany1 (lineComment <|> whitespaceText)

The error is on the second argument of both the <|> operators (over whitespaceText). The errors are -

Error   1   Type mismatch. Expecting a     Parser<string,'a>     but given a     Parser<char list,'a>     The type 'string' does not match the type 'char list'
Error   2   Type mismatch. Expecting a     Parser<string,'a>     but given a     Parser<char list,'a>     The type 'string' does not match the type 'char list'

It seems I need to convert a Parser<char list, 'a> to a Parser<string, 'a>. Or, since I'm just skipping them, I could convert them both to Parser<unit, 'a>. However, I don't know how to write that code. Is it some simple lambda expression?

Cheers!

Corral answered 6/12, 2011 at 3:53 Comment(2)
Parsing text as a char list and then converting the list to a string is pretty inefficient. It's better to use one of the parser combinators that directly return strings, see "Parsing strings directly" in quanttec.com/fparsec/reference/parser-overview.html That page also lists some whitespace parsers that you might find helpful. If you didn't yet have a look at the FParsec tutorial, you might find that helpful too: quanttec.com/fparsec/tutorial.htmlJongjongleur
Some unofficial tutorials helped a little more with understanding "how" to use FParsec. The links you gave are good as reference (especially to see what Parsers are available and how to do certain things). But for some basic parsing examples other tutorials might be easier to understand (especial if you don't know F# well as me ;) )Thurlough
S
2

let whitespaceText = manyChars (anyOf whitespaceTextChars)

or

let whitespaceText = many (anyOf whitespaceTextChars) |>> fun cs -> System.String (Array.ofList cs)

Superjacent answered 6/12, 2011 at 5:44 Comment(8)
Ah, rock dude! Thanks! I will use the first answer, but I'll also try to get a better intuition with the |>> operator.Corral
UPDATE: It now all type checks with either solution, however, I hit the following exception - System.InvalidOperationException : (Ln: 1, Col: 1): The combinator 'many' was applied to a parser that succeeds without consuming input and without changing the parser state in any other way. (If no exception had been raised, the combinator likely would have entered an infinite loop.) So this is very mind-boggling. I don't know of any way to have an FParsec parser parse comments as whitespace. Any ideas?Corral
The problem is (at least so I suspect) that you have many on whitespaceText and on skipWhitespace. Change whitespaceText from manyChars to many1Chars. Otherwise it'll just keep matching empty strings forever, never continuing beyond the skipMany. Note: this also applies to skipWhitespace1.Superjacent
Ah, yes, that's in the right direction. However, the final answer was to use let whitespaceText = anyOf whitespaceTextChars |>> fun chr -> string chr. Thank you for the guidance!Corral
System.String doesn't have an overload for char seq, at least as far as I can see in 4.5. Weird.Aves
@ReiMiyasaka This was a long time ago, but I'm guessing that you had a compilation error on the second alternative. I am quite surprised that I did not run that before posting, but it seems you are correct - use fun cs -> System.String (Array.ofList cs).Superjacent
@ReiMiyasaka This Q seems to be relevant: #2352276Grappa
@bytebuster Thanks, yeah, that's what I'm doing right now. I was hoping it wouldn't be necessary to create an intermediate array.Aves

© 2022 - 2024 — McMap. All rights reserved.