任意深度的行走OCaml元组

任意深度的行走OCaml元组,ocaml,type-inference,Ocaml,Type Inference,我试图更好地理解OCaml类型推断。我创建了这个示例: let rec f t = match t with | (l,r) -> (f l)+(f r) | _ -> 1 我想将它应用于任何具有嵌套对的二进制元组(对),以获得叶的总数。示例:f((1,2),3) 函数f拒绝编译,因为(f l)处的类型存在矛盾:“此表达式的类型为'a',但表达式的类型应为'a*'b” 问题:“a是任何类型的,也不能是一对,或者由uu案件处理?是否有任何方法可以遍历任意深度的元组而不

我试图更好地理解OCaml类型推断。我创建了这个示例:

let rec f t = match t with
    | (l,r) -> (f l)+(f r)
    | _ -> 1
我想将它应用于任何具有嵌套对的二进制元组(对),以获得叶的总数。示例:f((1,2),3)

函数f拒绝编译,因为(f l)处的类型存在矛盾:“此表达式的类型为'a',但表达式的类型应为'a*'b”

问题:“a是任何类型的,也不能是一对,或者由uu案件处理?是否有任何方法可以遍历任意深度的元组而不将它们转换为其他数据结构,例如变量


PS:在C++中,我会通过创建两个模板函数“F”来解决这类问题,一个处理元组和一个其他类型。

元组的任何组合都将有一个完全由它的类型描述的值形状(因为在类型结构中没有选择)-因此“叶子数”这个问题可以在编译时完全静态地回答。一旦有一个函数在这样的类型上运行-这个函数被固定为只在特定类型(和形状)上运行


如果你想构建一个可以有不同形状的树(但是相同的类型-因此可以由相同的函数处理)-你需要在混合中添加变体,例如经典的
类型'a tree=Leaf of'a | Node of'a tree*'树
,或者任何其他类型,用一些动态的“选择”形状来描述值。

有一种方法可以做到这一点,虽然我不会向新用户推荐它,因为这样会导致复杂性。您应该首先习惯于编写常规的OCaml

也就是说,通过捕获必要的结构作为GADT,您可以以通用方式遍历任意类型。对于这个简单的问题,它非常简单:

type 'a ty =
  | Pair : 'a ty * 'b ty -> ('a * 'b) ty
  | Other : 'a ty

let rec count_leaves : type a . a -> a ty -> int =
  fun a ty ->
    match ty with
    | Pair (ta, tb) -> count_leaves (fst a) ta + count_leaves (snd a) tb
    | Other -> 1
注意这里的
a ty
上的模式匹配与示例函数中的值模式匹配是如何对应的


使用更完整的类型表示可以编写更有用的函数,尽管一旦必须支持任意元组、记录、求和类型等,机器就会变得繁重和复杂。

f的类型是什么?我认为只是'a->int,所以它可以处理对和其他值…但这只是一个想法。如果
t
有一个完全未知的类型(
'a
),那么你就不能在它上面进行模式匹配。而且在f内部不可能声明两个辅助函数,一个专门用于对,另一个没有专门化,并根据f参数类型专门调用它们?无论如何,谢谢你的回答:)在我发布了我的问题后,我看到我的示例是一个“多态递归”(可能)的案例,似乎GADT可以帮助这些案例的类型推断。我将对此进行更深入的研究。你能用如何调用count_leaves来完成你的答案吗?因为我尝试了“count_leaves((1,2),3)”,它返回的是一个函数,而不是叶数?你还需要传递一个GADT值:
count_leaves((1,2),3)(Pair(Pair(Other,Other),Other))=>3
。(有人建议添加一种推理,它将为您生成这种相当乏味的GADT值,但这种语言尚未出现。)