【问题标题】:Mutually recursive datatypes相互递归的数据类型
【发布时间】:2015-06-21 16:34:39
【问题描述】:

我正在尝试创建一对相互递归的数据类型来表示 OCaml 中的红黑树,用于家庭作业。但是,我对 OCaml 语言非常不熟悉,所以我遇到了一些语法问题。

这是我目前的想法:

type 'a red_black_tree =
| RedNode of 'a * ( 'a black_node * 'a black_node )
| BlackNode of 'a black_node
and 'a black_node =
| TwoRedNodes of 'a * ( 'a RedNode * 'a RedNode )
| TwoBlackNodes of 'a * ( 'a black_node * 'a black_node )
| BlackLeaf;;

当我将它输入到 ocaml 时,它给了我:

utop # type 'a red_black_tree =
| RedNode of 'a * ( 'a black_node * 'a black_node )
| BlackNode of 'a black_node
and 'a black_node =
| TwoRedNodes of 'a * ( 'a RedNode * 'a RedNode )
| TwoBlackNodes of 'a * ( 'a black_node * 'a black_node )
| BlackLeaf;;
Error: Syntax error

您不能从子类型中引用类型的子值吗?不是在寻找问题的实际答案,只是语法说明。

更新

我在初次尝试后得到了这个,但教授说它不是一对相互递归的数据类型

type 'a red_black_tree =
| RedNode of 'a red_node
| BlackNode of 'a black_node
and 'a red_node =
| RedTree of 'a * ( 'a black_node * 'a black_node )
and 'a black_node =
| TwoRedNodes of 'a * ( 'a red_node * 'a red_node )
| TwoBlackNodes of 'a * ( 'a black_node * 'a black_node )
| BlackLeaf;;

更新 2

问题 3 红黑树是一种有时用于组织数值数据的树。它有两种类型的节点,黑色节点和红色节点。红色节点总是有一个数据和两个孩子,每个孩子都是一个黑色节点。黑色节点可能有: 1)一个数据和两个红色节点的子节点; 2)一个数据和两个子节点,即黑色节点;或 3) 没有数据也没有子节点(即叶节点)。 (这不是对红黑树的精确描述,但适用于本练习。)

编写一对相互递归的 OCaml 数据类型,表示红黑树中的红色节点和黑色节点。数据应该可以有任何类型,也就是说,你的类型应该是存储在树中的数据类型中的多态。

【问题讨论】:

    标签: recursion ocaml algebraic-data-types


    【解决方案1】:
    type 'a red_node = 'a * ('a black_node * 'a black_node)
    and  'a black_node = ('a * ('a node * 'a node)) option
    and  'a node =
        Red of 'a red_node
      | Black of 'a black_node
    

    一个表达式,它会根据您问题的最后更新告诉您“n”是什么类型的节点。

    (* to determine if a black node is a type 1 black node *)
    match n with
    | Black n' ->
        begin match n' with
        | Some n'' ->
            begin match n'' with
            | _, (Red _, Red _) -> "type 1 black node"
            | _, (Black _, Black _) -> "type 2 black node"
            | _ -> raise (Failure "invalid node")
            end
        | None -> "leaf node"
        end
    | Red _ -> "red node";;
    

    关于 OCaml 中类型的语义:OCaml 中的类型名称必须始终以小写字母开头(例如 listarrayref),但类型构造函数必须以大写字母开头(例如 @987654326 @)。该类型是一个包含其所有构造函数的伞。

    P.S.:我认为你甚至不需要相互递归的数据类型来解决这个问题。以下应该有效:

    type 'a node =
        Red of 'a * ('a node * 'a node)
      | Black of 'a option * ('a node option * 'a node option)
    

    【讨论】:

    • 我同意你对相互递归数据类型的需求,但可惜教授所说的不幸......
    • 我还不清楚的主要部分是:1)一条数据和两个红色节点的子节点; 2) 一个数据和两个子节点是黑色节点。 ('a node * 'a node) 如何限制这对是同质的?
    • 不受节点类型限制。使用这种类型时,您应该始终将其匹配为同质的。
    【解决方案2】:

    这是一个错误:

     | TwoRedNodes of 'a * ( 'a RedNode * 'a RedNode )
                                ^^^^^^^      ^^^^^^^
    

    这里RedNode应该是一个type构造函数,而不是值构造函数。我怀疑,您将要再添加一个类型 'a red_node 并定义您的 TwoRedNodes 分支,如下所示:

     | TwoRedNodes of 'a * ( 'a red_node * 'a red_node)
    

    【讨论】:

    • 我用这样的例子更新了我的帖子。然而,当我向教授提出这个建议时,她说这不是一对递归类型的例子
    • 也许她挑剔的不是一对,而是三倍? ;) 你可以向她指出这样一个事实,red_node 依赖于black_node,而black_node 依赖于red_node。不是相互递归的吗?
    • 教授有时可能会非常严格。我也会发布问题的描述。最坏的情况,我会交出我得到的东西,因为作业只有 5 / 200 分。
    【解决方案3】:

    最终,红黑树的一对相互递归数据类型的实现是:

    type ’a black_node = Leaf
    | RNode of ’a * ’a red_node * ’a red_node
    | BNode of ’a * ’a black_node * ’a black_node
    and ’a red_node = RedNode of ’a * ’a black_node * ’a black_node;;
    

    【讨论】:

      猜你喜欢
      • 2015-06-10
      • 1970-01-01
      • 1970-01-01
      • 2017-09-21
      • 1970-01-01
      • 2013-02-03
      • 1970-01-01
      • 2011-03-25
      • 1970-01-01
      相关资源
      最近更新 更多