【问题标题】:Walking OCaml tuples of arbitrary depth任意深度的步行 OCaml 元组
【发布时间】:2015-07-25 15:49:41
【问题描述】:

我试图更好地理解 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 是任何类型,不能也是一对,否则由 _ 情况处理?是否有任何方法可以遍历任意深度的元组而不将它们转换为其他数据结构,例如变体?

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

【问题讨论】:

  • f 的类型是什么?
  • 我认为只是'a->int,所以它可以处理对和其他值......但这只是一个想法。
  • 如果t 有一个完全未知的类型('a),那么你就不能对其进行模式匹配。
  • 而且 f 内部不可能声明两个辅助函数,一个专门用于对,一个没有任何专门化,并根据 f 参数类型专门调用它们?无论如何,谢谢你的回答:)

标签: ocaml type-inference


【解决方案1】:

有一种方法可以做到这一点,但由于其复杂性,我不会向新用户推荐它。你应该先习惯编写常规的 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 上的模式匹配与您的(键入错误的)示例函数中的值的模式匹配是如何对应的。

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

【讨论】:

  • 在我发布我的问题后,我看到我的示例是一个“多态递归”的案例(可能),似乎 GADT 可以帮助这些案例的类型推断。我会对此进行更多研究。你能用 count_leaves 的调用方式来完成你的答案吗,因为我尝试使用 "count_leaves ((1,2),3)" 它返回一个函数,而不是叶子的数量?
  • 您还需要传递一个 GADT 值:count_leaves ((1, 2), 3) (Pair (Pair (Other, Other), Other)) => 3
  • (有人提议添加一种推理,为您生成这种相当乏味的 GADT 值,但语言中还没有。)
【解决方案2】:

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

如果您想构建具有不同形状(但类型相同 - 因此可以由相同功能处理)的树 - 您需要添加变体到组合中,即经典 type 'a tree = Leaf of 'a | Node of 'a tree * 'a tree 或任何其他描述的类型具有某种动态“选择”形状的价值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-01
    • 2019-05-28
    • 1970-01-01
    • 1970-01-01
    • 2016-05-22
    • 1970-01-01
    • 2013-04-07
    • 2018-10-01
    相关资源
    最近更新 更多