Я пытаюсь рекурсивно искать значение поля в записи, которая является рекурсивным типом записи.
Мой тип записи
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
. То, как я прошел его, просто чтобы доказать свою логику, было:
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
соответствует тому, что я ищу, или если это пустой список.
Основное различие, которое я вижу между двумя моими реализациями, заключается в том, что первая продолжается до тех пор, пока не будут оценены все узлы, а вторая реализация продолжается до тех пор, пока я не найду то, что ищу.
Любые предложения будут оценены, и, если возможно, краткое объяснение того, где я ошибаюсь, или, по крайней мере, выделение того, где я ошибаюсь (я чувствую, что улавливаю много концепций функционального программирования, но есть еще несколько, которые ускользают от меня ).
let rec check name tree = tree.name = name || List.exists (check name) tree.branches
(имена сокращены, чтобы соответствовать комментарию) - person Andreas Rossberg   schedule 14.04.2017