Re: automatically resolving open?

Oleg <[email protected]> Thu, 24 Apr 2025 13:33:45 +0900
Newsgroups gmane.comp.lang.caml.inria
Message-ID <aAm/[email protected]>
First of all, to some small degree, such tool already exists: MetaOCaml

> open List
> let test = map (fun x -> x + 1) [1; 2; 3]
>
> I want to obtain:
>
> let test = List.map (fun x -> x + 1) [1; 2; 3]

   open List;;
   .<map (fun x -> x + 1) [1; 2; 3]>.;;

- : int list code = .<
Stdlib.List.map (fun x_1 -> x_1 + 1)
  (Stdlib.List.(::)
     (1, (Stdlib.List.(::) (2, (Stdlib.List.(::) (3, Stdlib.List.[]))))))>.

Everything is fully qualified: perhaps even more than
expected. MetaOCaml has functions to write the code to the file
(without the enclosing brackets). The obvious and major limitation is
that MetaOCaml brackets may only contain expressions (rather than
structures). Furtherfore, local modules etc. in those expressions are
not allowed (since it opens a huge can of worms for an uncertain
benefit: I'm not aware of any compelling example for allowing local
modules in brackets, which cannot be simply worked around in
traditional ways.)

> As far as I know there is currently no syntax for absolute
> paths in OCaml (every path is relative, and every name can
> be shadowed). Maybe we should consider adding such a syntax?

Actually, there is a hack for it in OCaml (OCaml source itself says
it's a hack.) See typing/typeclass.ml in OCaml repo and search for
"*predef*". It comes in the context of default arguments, which are
re-written during type checking into code using Some x and None. 
Those Some and None must be the pre-defined ones, rather than
locally re-defined. Thus the re-writing machinery produces
*predef*.Some and *predef*.None. The typing/env.ml and 
typing/persistent_env.ml has code to deal with
*predef*. Specifically, env.ml when asked to locale *predef*.l
looks up `l' in the initial environment.

It might be good to right this hack. The reason I care about it is
that naively pretty-printing Parsetree (converted from a Typedtree)
may produce identifiers like *predef*.None, which are not
syntactically valid. Therefore, I have to hack the pretty-printer to
ensure that the output is at least parseable, always. Incidentally,
the same typeclass.ml code also generates variable names like *sth*
and *opt* (I think typecore.ml has something similar). Now that we
have Ident.create_local, there is no need for such strange names.