Finding the recursive OCaml record type

I am trying to recursively search for a field value in a record, which is a recursive record type.

My post type

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

      

First, I tried to simply traverse the tree as a variable of this type:

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;

      

The idea is that it looks something like this:

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

      

So I'm looking for a record that has a field value node_name = foo_node

. The way I overcame this, just to prove my logic:

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

      

This gives:

[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

      

Now, I really want to just see if an instance exists, where node_name

is what I'm looking for, so I just want to return a boolean.

What I tried was (I created a new function for testing purposes only):

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

      

I am getting the following error in my function, I am navigating to 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 

      

Then I changed the last pattern matching block to

  | 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;

      

So, if the if conditions check the return of the function call and the kind of its passing. Now I have one error, but I still have the same error.

I understand that I List.iter

will pass each element of the passed list as the last argument to the function passed to List.iter

. So this should iterate over the elements of my list that I pass to it, and the only outputs are if the field node_name

matches what I'm looking for, or if it is an empty list.

The main difference I see between my two implementations is that the first one continues until all nodes have been evaluated, and the second implementation will continue until I find what I am looking for.

Any suggestions would be appreciated and, if possible, a short explanation of where I am going wrong, or at least highlight where I am going wrong (I feel like I am typing a lot of functional programming concepts, but there are a few more eluding me).

+3


source to share


1 answer


Well, in the last branch, if I understand well, you want to know if one of the nodes has a tail

good name. In this case, just use 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

      

And it will work as intended (note ||

between check_tree...

and List.exists ...

. If it check_tree ...

returns true

, you don't need to check the rest of the list.




A little explanation:

In OCaml, all pattern matching branches must be of the same type. Here your first branch was of type boolean

because you ended it with false

, and the second branch was of type unit

because you ended with List.iter ...

. List.iter

is of type ('a -> unit) -> 'a list -> unit

and applies its first argument to all elements of the list specified as the second argument. List.exists

is of type ('a -> bool) -> 'a list -> bool

and returns true

if one element in the list specified as the second argument satisfies the predicate specified as the first argument and false

if no such element exists.

Equivalently, if cond then e1 else e2

similar to pattern matching, so e1

both e2

must be of the same type, so the second try was just as wrong as the first .; -)

+4


source







All Articles