I am trying to use the pipe3
function from the FParsec
library but I get an error I don't know how to solve.
Given the Record
type Point = { x: float; y: float }
and the following parser
let plistoffloats' =
pipe3 pfloat (pchar ',' .>> spaces) pfloat
(fun first z second -> { x = first; y = second })
What I try to achieve is a parser that receives a string in format "1.1, 3.7"
and returns a Point
run plistoffloats' "1.1, 3.7"
Input : "1.1, 3.7"
Desired output : Point = {x = 1.1; y = 3.7;}
Error :
error FS0030: Value restriction. The value 'plistoffloats'' has been inferred to have generic type val plistoffloats' :
Parser <Point,'__a>
Either make the arguments to 'plistoffloats'' explicit or, if you do not intend for it to be generic, add a type annotation.
A simpler example with pchar
also didn't work.
let parsesA = pchar 'a'
error FS0030: Value restriction. The value 'parsesA' has been inferred to have generic type val parsesA :
Parser<char,'_a>
Either make the arguments to 'parsesA' explicit or, if you do not intend for it to be generic, add a type annotation.
This is covered in the FParsec documentation; it will happen with any parser. The reason is because in the .Net type system, functions are allowed to be generic, but values are not — and in FParsec, you're generally defining parsers as values (e.g., you're typically writing let psomething = ...
where psomething
takes no parameters). Read the linked documentation page for the whole explanation — I won't copy and paste the whole thing — but the short version is that you can do one of two things:
Create a test
function that looks like the following, and make sure it's used within the same source file on your parser:
let test p str =
match run p str with
| Success(result, _, _) -> printfn "Success: %A" result
| Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg
Annotate your parser with a type annotation like the following:
type UserState = unit // You might change this later
let plistoffloats' : Parser<_, UserState> =
// ...
It sounds like you're trying to do #1, but unless your parser is called with test plistoffloats'
in the same source file, the F# type inference won't be able to infer your user state type and will give you that error.
P.S. You can read more about the F# value restriction error here: Understanding F# Value Restriction Errors
P.P.S. The _
in the first position of Parser<_, UserState>
does not mean "This type could be anything" the way _
means in other contexts like pattern matching. Instead, _
in a type annotation means "Please infer this type for me so that I don't have to specify it explicitly". In FParsec contexts, this is very useful because all your parsers will have UserState
as their second type argument, but will have a varying type for the first type argument. And since the first type argument is the one that the type inference can infer, it means that you can copy and paste the type Parser<_, UserState>
to all your parsers and F# will Do The Right Thing™ in each case.