繁体   English   中英

搜索递归记录类型OCaml

[英]Search Recursive Record Type OCaml

我试图递归搜索作为递归记录类型的记录中的字段值。

我的记录类型是

type node = {node_name:string; node_branch:node list}

首先,我试图像这种类型的变量一样遍历一棵树:

let tree = {node_name="trunk"; node_branch=[{node_name="branch1L:1"; node_branch=[{node_name="branch2L:1"; node_branch=[]};
                                                                                  {node_name="foo_node"; node_branch=[]};];};
                                            {node_name="branch1L:2"; node_branch=[]}];}
    in
    let target = "foo_node" in
    print_newline();
    search_tree_for_name target tree;

这个想法是,它有点像这样:

                    trunk
            __________|_________
           |                    |
       branch1L:1           branch1L:2
    ______|_______
   |              |
branch2:1       foo_node

所以我正在搜索具有node_name = foo_node字段值的node_name = foo_node 我遍历它的方式,只是为了证明我的逻辑是:

let rec search_tree_for_name target_name in_tree =
  if in_tree.node_name = target_name then
    (* First check the node_name *)
      Format.printf "[%s] Target node_name found\n" in_tree.node_name
  else
    (* Then evaluate the branches *)
    begin
      match in_tree.node_branch with
      | [] ->
         Format.printf "[%s] Branches: 0; End of branch\n" in_tree.node_name
      | head :: tail ->
         Format.printf "[%s] Branches: %i\n" in_tree.node_name (List.length in_tree.node_branch);
         search_tree_for_name target_name head;
         List.iter (search_tree_for_name target_name ) tail;
    end

打印出:

[trunk] Branches: 2
[branch1L:1] Branches: 2
[branch2L:1] Branches: 0; End of branch
[foo_node] Target node_name found
[branch1L:2] Branches: 0; End of branch

现在,我真正想要的是看看是否存在一个实例,其中node_name是我正在寻找的,所以我只想返回一个布尔值。

我尝试的是(我创建了一个仅用于测试目的的新功能):

let rec check_tree_for_name target_name in_tree =
  if in_tree.node_name = target_name then
    begin
    (* First check the node_name *)
      Format.printf "[%s] Target node_name found\n" in_tree.node_name;
      true
    end 
  else
    (* Then evaluate the branches *)
    begin
      match in_tree.node_branch with
      | [] ->
         Format.printf "[%s] Branches: 0; End of branch\n" in_tree.node_name;
         false
      | head :: tail ->
         Format.printf "[%s] Branches: %i\n" in_tree.node_name (List.length in_tree.node_branch);
         check_tree_for_name target_name head;
         List.iter (check_tree_for_name target_name ) tail;
    end

我传递给List.iter函数出现以下错误:

Error: This expression has type node -> bool
       but an expression was expected of type node -> unit
       Type bool is not compatible with type unit 

然后我将最后一个模式匹配块更改为

  | head :: tail ->
     Format.printf "[%s] Branches: %i\n" in_tree.node_name (List.length in_tree.node_branch);
     if check_tree_for_name target_name head then true
     else List.iter (check_tree_for_name target_name ) tail;

因此if条件检查函数调用的返回和传递它的种类。 现在我少了一个错误,但我仍然有同样的错误。

我的理解是List.iter会将传递列表的每个元素作为传递给List.iter的函数的最后一个参数传递。 所以这应该迭代我传递给它的列表元素,唯一的出路是如果node_name字段匹配我要查找的或者它是一个空列表。

我在两个实现之间看到的主要区别在于,第一个实现持续到所有节点都被评估,第二个实现继续进行,直到找到我正在寻找的内容。

任何建议都会受到赞赏,如果可能的话,可以简单解释一下我出错的地方或至少突出我出错的地方(我觉得我正在学习很多功能性编程概念,但仍然有一些让我不知所措)。

好吧,在最后一个分支中,如果我理解得很好,你想知道tail一个节点是否有好名字。 在这种情况下,只需使用List.exists

| head :: tail ->
         Format.printf "[%s] Branches: %i\n" in_tree.node_name 
            (List.length in_tree.node_branch);
         check_tree_for_name target_name head ||
         List.exists (check_tree_for_name target_name ) tail

并且它将按预期工作(注意check_tree...List.exists ...之间的|| List.exists ...如果check_tree ...返回true ,则不需要检查列表的其余部分。


小解释:

在OCaml中,模式匹配的所有分支必须具有相同的类型。 在这里,你的第一个分支有一个boolean类型,因为你用false结束它,第二个分支有unit类型,因为你用List.iter ...结束它List.iter ... List.iter的类型为('a -> unit) -> 'a list -> unit ,并将其第一个参数应用于作为第二个参数给出的列表中的所有元素。 List.exists的类型为('a -> bool) -> 'a list -> bool ,如果作为第二个参数给出的列表中的一个元素满足作为第一个参数给出的谓词,则返回true ,如果不存在这样的元素,则返回false

同样地, if cond then e1 else e2就像一个模式匹配,所以e1e2应该具有相同的类型,所以你的第二次尝试与第一次尝试一样错误。 ;-)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM