I understand why let () = 1 + 2
leads to an error message when ()
is redefined. My question is why utop would be rewriting 1 + 2
as let () = 1 + 2
, since it seems that the latter should lead to an error message even when ()
isn’t redefined.
The full rewriting rule for utop is that is first evaluated as
let _ () = let module _ = struct <expr> end in ()
in order to check the expression without evaluating it.
Slightly off-topic, but another way I find redefining []
and (::)
useful locally is when combining them with GADTs and existential types to implement kinds of DSLs.
A recent example was for heterogenous pretty printing of parameters:
let module M = struct
type t =
| []
| (::) : ((formatter -> 'a -> unit) * 'a) * t -> t
let rec pp_ls fmt = function
| [] -> ()
| (pp, v) :: [] -> pp fmt v
| (pp,v) :: tl -> pp fmt v; pp_print_string fmt ","; pp_print_space fmt (); pp_ls fmt tl
end in
and then instantiating them:
(pp_rule "Read" M.[pp_print_string, var; pp_print_int, offset])
(where var
is of type string, and offset
of type int).
1 Like