Types 存在量化类型参数、递归函数与类型错误

Types 存在量化类型参数、递归函数与类型错误,types,ocaml,gadt,existential-type,Types,Ocaml,Gadt,Existential Type,考虑以下一段OCaml代码: type mytype = My : 'a list * 'a -> mytype let rec foo : int -> mytype = fun n -> if n < 0 then My([], 2) else let My(xs, y) = foo (n - 1) in My(3::xs, y) 但是假设我真的不想改变mytype的定义。假设我想保留该函数的行为(非工作代码可以直观地理解)

考虑以下一段OCaml代码:

type mytype = My : 'a list * 'a -> mytype

let rec foo : int -> mytype =
    fun n -> if n < 0 then My([], 2)
        else let My(xs, y) = foo (n - 1)
        in My(3::xs, y)
但是假设我真的不想改变
mytype
的定义。假设我想保留该函数的行为(非工作代码可以直观地理解),那么我是否可以编写
foo


另外,有人能解释问题的根源是什么,即为什么初始代码没有进行类型检查吗?

当对
mytype
值进行模式匹配时,无法知道其内部是什么类型。问题是,类型系统的行为非常简单,即使mytype来自递归调用,也不会试图知道它来自何处(类型系统就是不能这样工作)

问题是,你知道在这种情况下,
'a
确实是
int
,但是你需要给编译器一个证明

在这种情况下,您不需要这样做。您只需在函数结束时使用GADT:

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)
在上面的GADT中,您可以看到没有任何东西表明列表中的每个元素都是相同类型的。事实上,如果你得到一个
mylist
,你就无法知道里面是什么元素

所以,你需要证明这一点。这样做的一个好方法是在gadt中存储类型证明:

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
现在,当打开a
mytype
时,您可以在证明上匹配以证明'a'的值。编译器将知道它是相同的,因为它将拒绝创建没有与正确类型对应的证明的mytype


正如您所看到的,GADT并不简单,在开始实现之前,您通常需要做几个草案。大多数情况下,您可以避免使用它们(如果您不确定它们是如何工作的,请不要使用它们)。

请您进一步说明一下,如何向编译器证明某些类型确实是相同的?我怎样才能做到呢?我添加了一些信息,我会让你在网上搜索更完整的例子和教程。
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 *)
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