List 搜索递归记录类型OCaml
我正在尝试递归地搜索一个属于递归记录类型的记录中的字段值 我的唱片类型是List 搜索递归记录类型OCaml,list,recursion,ocaml,record,List,Recursion,Ocaml,Record,我正在尝试递归地搜索一个属于递归记录类型的记录中的字段值 我的唱片类型是 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=[]};
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\u name=foo\u 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\u name
就是我要寻找的,所以我只想返回一个布尔值
我尝试的是(我创建了一个新函数只是为了测试):
我传递给列表的函数出现以下错误。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
的函数。因此,这应该迭代我传递给它的列表元素,唯一的出路是节点\u 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
它将按预期工作(注意检查树…
和列表存在…
之间的检查树…
。如果检查树…
返回true
,则无需检查列表的其余部分
小说明: 在OCaml中,模式匹配的所有分支必须具有相同的类型。在这里,第一个分支具有
布尔类型,因为您以false
结束,第二个分支具有unit
类型,因为您以List.iter…
List.iter
类型('a->unit)->'a list->unit
,并将其第一个参数应用于作为第二个参数给出的列表中的所有元素。
List.exists
的类型为('a->bool)->'a List->bool
,如果作为第二个参数给出的列表中的一个元素满足作为第一个参数给出的谓词,则返回true
,如果不存在这样的元素,则返回false
同样地,if cond then e1 else e2
类似于模式匹配,因此e1
和e2
应该具有相同的类型,因此您的第二次尝试与第一次尝试一样错误;-此外,值得注意的是List.exists
是一个快捷操作符:它将在“有效”之后立即返回元素已遇到。如果您想亲自查看:List.exists(乐趣x->print_int x;x=3)[1;2;3;4;5]代码>谢谢,对我来说这是显而易见的,但值得一提是的,这是OP和其他人的旁注谢谢你的解释!这是有道理的。我认为程序流会进入List.iter调用的函数,然后退出。我没想到它会回来。但现在我在列表文档中也看到了它返回的单元。感谢@RichouHunter的澄清,这很有帮助!Lhooq的答案是正确的,但我还想指出,您所寻求的函数实际上是一行:让rec检查name tree=tree.name=name | | List.exists(check name)tree.branchs
(名称缩短以适合注释)@AndreasRossberg谢谢您,很高兴看到更多的惯用方法
| 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