2

I have this question about matching functions by its signature. I am asking this for learning purposes and I do understand that there are many ways of going around this.

Suppose that in F# I have the following analogous types:

type T1 = int * int * int
type T2 = {a:int ; b:int; c:int}

And the conversion between them is as trivial as

let convert p =
    match p with
    |(x,y,z) -> {a = x; b = y; c = z}

Suppose also that I have a substantial library of functions that were written for using with T1 that I now want to reuse with T2, such as:

let addT1 a b =
    match a, b with
    |(x1,y1,z1),(x2,y2,z2) -> (x1 + x2, y1 + y2, z1 + z2)

let negT1 = 
    function
    |(x,y,z) -> (-x,-y-z)

let offset a i =
    match a with
    |(x,y,z) -> (x + i, y + i, z + i)

As you can see, all functions rely on T1 but may get multiple parameters of T1 or parameters of other types.

I am familiar with this, witch allows me to map any function (f: int * int * int -> 'a) to a function (g: T2 -> 'a):

let funcOfT2 f = fun (t:T2) -> f (t.a, t.b, t.c)

But in the case of addT1, for example, this does not work because of the second parameter:

val addT1 : int * int * int -> int * int * int -> int * int * int
val (funcOfT2 addt1) : (T2 -> int * int * int -> int * int * int)

So, to use a function like funcOfT2 I would have to use it like this, witch is impractical:

let p1 = {a = 1; b = 2; c = 3}
let p2 = {a = 2; b = 3; c = 4}
let x = funcOfT2 (funcOfT2 addT1 p1) p2
val x = int * int * int = (3,5,7)

I could also make a local version of each function of T1 passing the necessary amounts of funcOfT2 or use convert every time I use a Function of T1, but I believe it would be really impractical and make a cluttered code.

Is there anyway of matching the signature of a function so that I can convert any function that takes any T1 to a function of T2?

My idea was something like this, it does not work for many reasons, but I think it may exemplify what I wanted. Is there any way to do it?:

let rec myDream f =
    match f with
    |(g: T1 -> 'a) -> fun (t:T2) rest -> fOfT2 (g (convert t)) rest
    |(g: 'b -> 'c) -> fun x y -> fOfT2 (g x) y
    |(g: 'd) -> g d
  • Isn't it easier to convert the arguments instead of converting the functions? – Gus Mar 08 '18 at 21:46
  • Yes, for pratical purposes. My intention, instead, is to learn and know if there is any way to do a generic function mapping with this kind of signature matching. If something like this was possible it would be pretty powerful. It would basically mean that if I can convert between two types, I can use all available functions of the other type without having to wrap them individually. – UsuarioBeta Mar 08 '18 at 23:06
  • I can try to find a way using static constraints, but I promise you it will be very hacky. Only very advanced users will be able (after some mental gymnastics) to understand what's going on. – Gus Mar 09 '18 at 06:56

0 Answers0