The following problems arise in the context of a patch for adding support for bigarrays to the ocamlmpi library. I don’t know how to solve the third problem. I have a vague intuition that it is not possible, but I would love to be proved wrong or to really understand why it cannot be done.
You are given a list of operations (e.g., Maximum and Logical-And). All of them apply to integer values but only some of them (e.g., Maximum) apply to floating-point values.
Constraint 1: The operations must be modeled by a single variant type.
Problem 1 (easy): give the signature of a function from an int and any operation to an int.
Problem 2 (harder): give the signature of a function from a float and a floating-point-only operation to a float.
Problem 3 (unknown): give the signature of a function from a list of int, char, or float and an operation to unit. When the list contains floats, only floating-point operations are allowed.
Here is my attempt. It solves problems 1 and 2 but fails to solve problem 3.
type _ op = | Max : [< `Int of int | `Char of char | `Float of float ] op | Land : [< `Int of int | `Char of char ] op module type S = sig val reduce_int: int -> [`Int of int ] op -> int val reduce_float: float -> [`Float of float] op -> float val reduce_list: 'a list -> [< `Int of 'a | `Char of 'a | `Float of 'a ] op -> unit end module A : S = struct let reduce_int x op = x let reduce_float x op = x let reduce_list s op = () end let _ = A.reduce_int 0 Max (* OK *) let _ = A.reduce_int 0 Land (* OK *) let _ = A.reduce_float 0. Max (* OK *) let _ = A.reduce_float 0. Land (* OK: REJECTED *) let _ = A.reduce_list  Max (* OK *) let _ = A.reduce_list  Land (* OK *) let _ = A.reduce_list [0.] Max (* OK *) let _ = A.reduce_list [0.] Land (* KO: NOT REJECTED! *)
The problem can be solved using module types if constraint 1 is dropped, but this solution seems more bureaucratic than elegant.
Anyone have a better idea?