Non-stringly invocation in PPX

Consider the fragment from a PPX shown at the end. The example is nonsensical,
but it illustrates a real-world problem: a PPX that produces code where a
certain function call is not always the same.

I know that this particular dummy example would be better solved without a PPX
because functions are first-class values in OCaml, but please bear with me.
Just imagine that the PPX must generate code that invokes a certain function
but without ever revealing the alternative functions in the generated code.
(In the example below, the generated code invokes Int64.add 50% of the time,
and Int64.sub the other 50%, but the unchosen function is not revealed in the
generated code.)

Anyway, the example sort of works, in the sense that invoking ocamlc
with -dsource produces the result I want, but in practice it has two
serious problems:

  1. Embedding the function identifiers in f_str inside strings is ugly
    and error-prone.

  2. It seems that module discovery is not re-run after the PPX, which
    causes the at-first perplexing error that the compiler complains
    about unknown modules, but if the code obtained via -dsource is
    re-fed manually to the compiler, then it works…

Anyway, I’m wondering if there’s a way to redefine f_str instead as
let f_str = if Random.bool () then Int64.add else Int64.sub
(note that it’s no longer stringly-typed), and then somehow
create an expression that references either Int64.add or Int64.sub.

let f_str = if Random.bool then "Int64.add" else "Int64.sub" in
let f_ident = Ast_builder.Default.pexp_ident ~loc (Loc.make ~loc (Lident f_str))
let make_expr ~loc = [%expr [%e f] 4L 1L]

Thanks in advance for your attention!

First, there is a bug in your code Lident "Int64.add" does not produce a qualified identifier
(that would be Ldot(Lident "Int64", "add")) but a syntactically impossible ident Int64.add (in one token).

Ah, thanks! I reckon that explains why the compiler complains about unknown functions, but if I take the output from -dsource and try to compile it then it works fine.

Anyway, one problem solved. But is there a way to avoid the stringly-typed functions?

You could use:

let f x =
  if Random.bool () then
    [%expr Int64.add [%e x]]
  else [%expr Int64.sub [%e x]] 

But at the end of the day, a name is a string.