The following top-level XML parser definition returns the error The value or constructor ‘TOP_LEVEL_RECORD’ is not defined.
…
let xTop_Level, xTop_Level_Ref = createParserForwardedToRef<TOP_LEVEL_RECORD, unit>()
do xTop_Level_Ref :=
pipe4
(opt xDeclaration)
(opt (many xComment_or_CData))
xElement
(opt (many xComment_or_CData))
(fun decl before_root root after_root
-> {Declaration = decl
Before_Root = before_root
Root = root
After_Root = after_root}) |>> TOP_LEVEL_RECORD
// This returns the error -------------------→^^^^^^^^^^^^^^^^
TOP_LEVEL_RECORD
is defined as …
type TOP_LEVEL_RECORD = {Declaration : XDECLARATION option
Before_Root : COMMENTS_OR_CDATA list option
Root : XELEMENT
After_Root : COMMENTS_OR_CDATA list option
}
The parsers xDeclaration
, xCommentor_Cdata
, and xElement
are all correctly defined and return the corresponding types in the TOP_LEVEL_RECORD
.
The let xTop_Level, xTop_Level_Ref = createParserForwardedToRef<TOP_LEVEL_RECORD, unit>()
is Fparsec’s syntax for recursive parser calls documented here: http://www.quanttec.com/fparsec/tutorial.html#parsing-json.createParserForwardedToRef-example.
If I define the type type TOP_LEVEL = TOP_LEVEL_TYPE of TOP_LEVEL_RECORD
and replace TOP_LEVEL_RECORD
with TOP_LEVEL
and TOP_LEVEL_TYPE
as follows …
let xTop_Level, xTop_Level_Ref = createParserForwardedToRef<TOP_LEVEL, unit>()
// Replaced this text ------------------------------------->^^^^^^^^^
do xTop_Level_Ref :=
pipe4
(opt xDeclaration)
(opt (many xComment_or_CData))
xElement
(opt (many xComment_or_CData))
(fun decl before_root root after_root
-> {Declaration = decl
Before_Root = before_root
Root = root
After_Root = after_root}) |>> TOP_LEVEL_TYPE
// Replaced this text ----------------------->^^^^^^^^^^^^^^
... the code compiles without any errors or warnings.
Why does TOP_LEVEL_TYPE
have a constructor here and not TOP_LEVEL_RECORD
?
Can you point me to the relevant part of the F# or FParsec documentation?
TOP_LEVEL_RECORD
(a record type) and TOP_LEVEL
(a union type) are type names and cannot be used as constructors.
To construct a TOP_LEVEL_RECORD
you use the syntax as in your code
{ Declaration = decl
Before_Root = before_root
Root = root
After_Root = after_root }
To construct an instance of a union type, you use one of the case names as a constructor function; TOP_LEVEL_TYPE
in your case, since there's only one union case.
Note that in your type definition
type TOP_LEVEL = TOP_LEVEL_TYPE of TOP_LEVEL_RECORD
TOP_LEVEL
is a type, but TOP_LEVEL_TYPE
(despite its name) is not a type, but a constructor function for the TOP_LEVEL
type.
So record types do not have named constructor functions, but union types do.
For your code, you can just skip the |>> TOP_LEVEL_RECORD
part.
You can read about record types and union types in F# language spec, sections 8.4 and 8.5.