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!

Guy Coder
  • 24,501
  • 8
  • 71
  • 136
Bryan Edds
  • 1,696
  • 12
  • 28
  • 1
    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 http://www.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: http://www.quanttec.com/fparsec/tutorial.html – Stephan Tolksdorf Dec 06 '11 at 09:13
  • 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 ;) ) – Daniel Bişar Jul 30 '20 at 11:45

1 Answers1

2

let whitespaceText = manyChars (anyOf whitespaceTextChars)

or

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

Ramon Snir
  • 7,520
  • 3
  • 43
  • 61
  • Ah, rock dude! Thanks! I will use the first answer, but I'll also try to get a better intuition with the |>> operator. – Bryan Edds Dec 06 '11 at 08:08
  • 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? – Bryan Edds Dec 06 '11 at 08:08
  • 2
    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. – Ramon Snir Dec 06 '11 at 08:18
  • 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! – Bryan Edds Dec 06 '11 at 16:46
  • `System.String` doesn't have an overload for `char seq`, at least as far as I can see in 4.5. Weird. – Rei Miyasaka Oct 02 '12 at 18:08
  • @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)`. – Ramon Snir Oct 03 '12 at 06:57
  • @ReiMiyasaka This Q seems to be relevant: http://stackoverflow.com/questions/2351776/convert-a-list-of-characters-or-array-to-a-string – Be Brave Be Like Ukraine Oct 03 '12 at 11:37
  • @bytebuster Thanks, yeah, that's what I'm doing right now. I was hoping it wouldn't be necessary to create an intermediate array. – Rei Miyasaka Oct 03 '12 at 16:20