Hello I’m playing with ocamllex. Here’s an ocamllex file
{
type res = ENDOFFILE | OK
}
rule test = parse
['0' - '9']+
{ OK } |
[' ' '\t']+
{ OK } |
_
{OK} |
eof
{ENDOFFILE}
And the main file
let scan inp:string =
let lb = Lexing.from_string inp in
let rec run (s:string) =
match Lex.test lb with
ENDOFFILE -> s ^ "\nend" |
_ -> run (s ^ " \nfound something at " ^ string_of_int (Lexing.lexeme_start lb))
in
run "start\n"
let _ = print_endline (scan "42 24")
I ran ocamllex then I compiled the result with ocamlopt. The code works. I had to specify the module of the “test” function but not the ENDOFFILE value (the ugly name is choosen to be sure it is mine). Is it normal practise or some accident ?
This is called type-directed disambiguation (see OCaml - The core language). In contexts where the compiler has enough type information, it can use that information to look up constructor and record label names in the right scope, even if they are not prefixed with the module path where they are defined.
It is convenient and of rather normal usage, I would say.
Incidentally, I found it surprising that the pattern match is not used to infer the correct type in this example on the linked manual page:
let is_a_or_b x = match x with
| A -> true (* OCaml infers [x: last_variant] *)
| B -> true;;
Error: This variant pattern is expected to have type last_variant
There is no constructor B within type last_variant
Is this more complicated / less well defined to do than using usages of record fields to disambiguate?
type middle_record = { x:int; z:int }
type last_record = { x:int }
let f r = r.x + r.z
cannot infer that r should be middle_record, which surprised me (at least in utop). Naively, one would think that this should be simple to do. But I wouldn’t be surprised to learn that it cannot be made to work in a reasonably general way.