The shadowing trick allows the users to overwrite the usual arithmetic
operators (+, -, ...)
with their own by simply doing let open My_module in ...
. However the litterals in the program are
still interpreted as integer or floats by OCaml's parser which forces
the programmers to write boilerplate code to handle these cases.
Wideopen is a syntax-extension that allows you to use a custom parsing
utility for OCaml's litterals using by default the of_string
function of the specified module.
For example, the following piece of code (which uses the Zarith library) computes the number of solutions of a quadratic equation:
let nb_solutions a b c =
let open[@parse.int] Z in
let delta = b * b - 4 * a * c in
if delta > 0 then 2
else if delta = 0 then 1
else 0
Which is syntactic sugar for:
let nb_solutions a b c =
let open Z in
let delta = (b * b) - (of_string "4") * a * c in
if delta > (of_string "0")
then of_string "2"
else if delta = (of_string "0") then of_string "1" else of_string "0"
Whenever an [@parse.]
annotation is met, the litterals
l
appearing in the sub-expression are replaced with
(of_string l)
. Also, note that as this extension works on the
Parsetree of OCaml, we are able to handle litterals of arbitrary size
(e.g. greater than 2^64), given that the parsing function being used
accepts it.
Wideopen provides three different annotation:
-
[@parse.int]
which replaces only the integer litterals (thePconst_integers
constructor of OCaml'sParsetree
) -
[@parse.float]
which replaces only the float litterals (thePconst_float
constructor of OCaml'sParsetree
) -
[@parse.all]
which replaces both float and integer litterals.
Note that the latter annotation allows you in particular to manipulate
"integers" and "floats" indiferently as a "bigger type" (Zarith's
rationals using the Q
module for example) without having to
care about int-float conversion and operators.
By default, Wideopen uses the of_string
of the specified
module. However, to avoid having to define such a function within our
modules, we can specify the name of the function to be used for the
parsing as in the following example:
let open[@parse.all using parse] Mymodule in ...
Which parses both integers and floats using the parse
function
of the module Mymodule