行走任意深度的OCaml元组

时间:2015-07-25 15:49:41

标签: ocaml type-inference

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

let rec f t = match t with
    | (l,r) -> (f l)+(f r)
    | _ -> 1

我希望将它应用于任何具有嵌套对的二进制元组(对),以获得叶子的总数。示例:f((1,2),3)

函数f拒绝编译,因为(fl)类型中存在矛盾:"此表达式具有类型' a但表达式需要类型' a *' b"

问题:' a是任何类型,也不能是一对,或者由_ case处理?是否有任何方法可以将任意深度的元组转换为其他数据结构,例如变体?

PS:在C ++中,我会通过创建两个模板函数来解决这类问题,#34; f",一个用于处理元组和另一个类型。

2 个答案:

答案 0 :(得分:5)

有一种方法可以做到这一点,但由于产生的复杂性,我不建议将它推荐给新用户。你应该习惯先写一些常规的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上的模式匹配如何对应于(类型不佳)示例函数中值的模式匹配。

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

答案 1 :(得分:3)

元组的任何组合都将具有完全由其类型描述的值形状(因为在类型结构中没有"选择")因此"叶子的数量和# 34;问题可以在编译时完全静态地回答。一旦你有一个在这种类型上运行的功能 - 这个功能被修复为仅对特定类型(和形状)进行操作。

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