is it possible to have an entirely static ad hoc polymorphism, or does it always require dynamic calls? @lpw25, do modular implicits have some dereference overhead?
That requires monomorphisation (i.e. a different copy of a polymorphic function for each type it is used at). Rust does that, as does MLton for Standard ML. However, it can’t be done in general for OCaml, a number of features allow new instances to of polymorphic functions to be generated at run time (e.g. polymorphic recursion). It also has downsides in terms of code size and compile time.
However, monomorphisation is really a special case of specialising a function to known arguments. Flambda already does this. For example, given:
let sum l = List.fold_left (fun acc x -> acc + x) 0 l
flambda can create a new copy of List.fold_left specialised to (fun acc x -> acc + x). Whether it does this is based on its own heuristics that try to judge whether the improvements from specialising the function outweigh the cost of the increased code size.
The same should work for implicits. Given:
module type Print = sig type t val print : t -> string end
let print {P : Print} x = P.print x
implicit module Print_int = struct
type t = int
let print = int_of_string
end
let print_ints (l : int list) =
List.map (fun i -> print i) l
then flambda should automatically specialise the print function to the (implicit) argument Print_int and the whole thing should reduce down to just calling int_of_string.