type Mul = Mul with member inline __.Op(a: ^a,b: ^a) = a*b
type Div = Div with member inline __.Op(a: ^a,b: ^a) = a/b
type Add = Add with member inline __.Op(a: ^a,b: ^a) = a+b
type Sub = Sub with member inline __.Op(a: ^a,b: ^a) = a-b
let inline op x a b =
(^a: (member Op: ^b * ^b -> ^b) x,a,b)
let inline tup2 a b c d = op Mul a b, op Mul c d
let inline tup2' f a b c d = op f a b, op f c d
let a = tup2 1 2 3.0f 4.0f
//let b = tup2' Mul 1 2 3.0f 4.0f //Gives a type error.
I am wondering if there is a way to make the types do what I want in the example above or if I have finally reached the limitation of F#'s type system. Actually, there is a way to make the above work and that is to put all the types into one DU and then pattern match on the DU type like the following:
type Operation =
| Mul
| Add
| Sub
| Div
member inline t.Op a b =
match t with
| Mul -> a * b
| Add -> a + b
| Sub -> a - b
| Div -> a / b
let inline map' (f: Operation) a b c d =
(f.Op a b, f.Op c d)
map' Mul 1 2 3.0f 4.0f
But assuming the first example worked, it would be a more dynamic solution. It is a pity something like passing a higher order function by name inside an argument and having it inlined on the spot to make it generic is not possible.