When a pattern matching is done on a mytype value, there is no way to know what type is inside. The thing is, the typing system acts quite simply and doesn't try to know where the mytype is from even if it comes from a recursive call (the typing system just doesn't work that way).
The thing is, you know in that case that the 'a is indeed int, but you need to give a proof of that to the compiler.
In that specific case, you don't need to. You just need to use the GADT only at the end of your function:
let foo n =
let rec aux n =
if n < 0 then ([], 2)
else let (xs, y) = aux (n - 1)
in (3::xs, y)
in
let (xs,y) = aux n in My (xs,y)
It is worth noting that with that type definition, there is no way for you to use the fact that you know there are integers values in your mytype, so it will be pretty unusable. GADTs should be used only in specific cases and you should precisely know why and how you'll be using them.
EDIT:
A type can be seen as a logical formula attached to every value. In most cases, it is pretty simple and you don't have to worry about it, mostly because type variables ('a 'b and so forth) are universally quantified and always visible to the exterior of the type.
type 'a mylist = Cons of 'a * 'a list | Nil
(* should be read as:
for all 'a,
'a mylist is either
* a cons containing the same 'a and 'a list
* nil *)
type mylist = Cons : 'a * mylist -> mylist | Nil : mylist
(* should be read as:
mylist is either
* for some 'a, a 'a and another list
* nil *)
In the GADT above, you can see that nothing states that every element in the list is of the same type. In fact, if you get a mylist, you have no way of knowing what element is inside.
So, you need to prove it. A good way of doing so is to store inside the gadt a proof of type:
type _ proof =
| Int : int proof
| Float : float proof
| Tuple : 'a proof * 'b proof -> ('a * 'b) proof
(* You can add other constructors depending on
the types you want to store *)
type mytype = My : 'a proof * 'a list * 'a -> mytype
Now with this, when opening a mytype, you can match on the proof to prove the value of 'a. The compiler will know it's the same because it would refuse to create a mytype without a proof corresponding to the right type.
As you can see, GADTs are not simple, and you often need to do several drafts before going to implementation. Most of the time, you can avoid using them (and if you're not sure of how they work, don't use them at all).