Types 存在量化类型参数、递归函数与类型错误
考虑以下一段OCaml代码: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的定义。假设我想保留该函数的行为(非工作代码可以直观地理解)
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
现在,当打开amytype
时,您可以在证明上匹配以证明'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