[erlang-questions] Noob questions: Searching a tree

Richard O'Keefe ok@REDACTED
Thu Dec 11 05:12:53 CET 2008

On 10 Dec 2008, at 12:25 am, Edward Stow wrote:

> Hi
> Is this a friendly place to ask very simple questions about Erlang and
> functional programming.  I'm learning both at the same time.  For
> example I want to search for a value in the nodes of a tree structure.
> The tree is simply nested lists.  For example
> 6> tut1:search(a, [b, [a]]).
> true
> 7> tut1:search(a, [b, [c]]).
> false
> 8> tut1:search(a, [ [a], b]).
> true

The starting point is a question:
"What do you *mean* 'the tree is simply nested lists'?"
Can a "value" ever be a list itself?
If so, does the "value" [a,b] occur in the list [c,a,b]?

Haskell programmers talk about "rose trees"
where a rose tree is a node that has a value and 0 or more subtrees.

is_rose_tree({Value,Children}) ->
is_rose_tree(_) ->

is_rose_tree_list([Tree|Trees]) ->
     case is_rose_tree(Tree)
       of true  -> is_rose_tree_list(Trees)
        ; false -> false
is_rose_tree_list([]) ->
is_rose_tree_list(_) ->

The nice thing about starting by writing down a recogniser
for a recursive data structure is that computations on it are
often straightforward edits of the recogniser.


member_rose_tree(X, {X,_}) -> true;
member_rose_tree(X, {_,L}) -> member_rose_tree_list(X, L).

member_rose_tree_list(X, [T|Ts]) ->
     case member_rose_tree_list(X, T)
       of true  -> true
        ; false -> member_rose_tree_list(X, Ts)
member_rose_tree_list(_, []) ->

Note that with this representation a rose tree CAN be a value
in a rose tree, and there is never any doubt about which bits
are values held in the tree and which are substructure.

Of course this is prettier in Haskell:

	data Rose_Tree t = Rose_Tree t [Rose_Tree t]

	x `elem` (Rose_Tree y ts) = x == y || any [x `elem` t | t <- ts]

but the Erlang version is also straightforward.
> My implementation is: Is this implementation OK or how else would it
> be performed.
> -module(tut1).
> -export([search/2]).
> %% Search for an element in tree (nested lists)
> search(_, []) ->
>    false;
> search(A, [A|_]) ->
>    true;
> search(A, [H|T]) when list(H), length(H) > 0 ->
>    [H1|T1] = H,
>    search(A, [H1 | [T1 | T]]);
> search (A, [_|T]) ->
>    search(A, T).

length/1 is an order N operation.  In this context,
you simply don't need it.  Your third rule could
just be
	search(A, [[H1|T1]|T]) ->
	    search(A, [H1|[T1|T]]);

 From your definition, you ARE willing to accept a list as a value
in a nested list, and you are even willing to accept [a,b] as
one of the values in [c,a,b] --- I would NOT be --- so you could
simplify the whole thing to

	search(A, A) ->
	search(A, [H|T]) ->
	    case search(A, H)
	      of true  -> true
	       ; false -> search(A, T)
	search(A, _) ->

It's not quite the same, but close enough for government work.

I do think that a clearer separation between "payload" and
"structure" would be a good idea, as in the "rose tree" datatype
described above.
> Question:  I'm not really sure of the semantics of the comma operator
> in the function when clause:
> search(A, [H|T]) when list(H), length(H) > 0 ->

It means "AND".
> Can somebody point me towards some relevant documentation.

Either the old Erlang book or Joe's new Erlang book.
The on-line reference manual, which is at
describes guards in "6.24 Guard Sequences",
which you can reach from the navigation bar on the left.

More information about the erlang-questions mailing list