Nick Zuber
Nick Zuber

Reputation: 5637

Is it possible to have a function accept two different sum types that have the same definition?

Let's consider two different but similar sum types:

(* Two different types, but same/similar definitions *)
type t = Foo of int
type t' = Foo of int

and then let's imagine we had a function that could work with either type at face value:

(* Function that could work with either t or t' *)
let f x = 
  match x with
  | Foo n -> n

Is it possible for that function f to actually work with both types t and t' when they are both sum types?

I know that when the function is processed for its type, x will be inferred to have type t' and then not be compatible with type t.

let _ = 
  let (a : t) = Foo 1 in
  let (a' : t') = Foo 1 in
  let _ = f a' in (* This is fine. *)
  let _ = f a in  (* This will throw a type error. *)
  ()

Alternatively, I know using a simpler type would work fine, like:

type t = int
type t' = int

let g x = x + 1

let _ =
  let (a : t) = 1 in
  let (a' : t') = 1 in
  let _ = g a' in (* This is fine. *)
  let _ = g a in  (* This is fine. *)
  ()

I'm guessing this works because g will get inferred to have the type int -> int which is compatible with both t and t' in this case since they are truly of the same type, whereas in my previous example they were separate sum types that just happened to have the same structure.

So to reiterate my question, is it possible for that function f to actually work with both types t and t' when they are both sum types?

I'm asking because I want to know if I have to write the same function for both t and t' (essentially duplicating code since both types would be handled exactly the same).

Upvotes: 1

Views: 62

Answers (1)

PatJ
PatJ

Reputation: 6140

No

Your types t and t' may have similar definition, but they are different types.

However, you can go around that.

Since in the comments you stated that you had no control over the type declaration, the only way I see to solve your problem is the functor way.

type a = A
type a' = A

module type T = sig type t = A end

module A ( X : T ) = struct open X let f = function A -> () end

module T1 = struct type t = a = A end
module T2 = struct type t = a' = A end
module A1 = A(T1)
module A2 = A(T2)

However, if a library gave you two types like that, it is probable there is a reason for it and a way to do things differently provided by the library itself.

Upvotes: 3

Related Questions