I end up writing code that looks like this:
let some_fn (type a b) (a : a) (b : b) = ...
But sometimes I can't, and I have to write things this way:
let some_fn : type a b . a -> b -> unit = fun a b -> ...
But sometimes I can also write
let fn : 'a 'b . 'a -> 'b -> unit = fun a b -> ...
I understand that the first one is a locally abstract type, which is used to make sure that the type checker doesn't allow function logic that treats a
as b
(no type unification), but it also seems useful for GADTs for some reason?
The second one seems mandatory when using some features of GADTs, although I'm still perplex on why.
The third one seems like it's equivalent to
let fn (a : 'a) (b : 'b) = ...
but I'm not entirely sure.