[mercury-users] Help: generic tree predicates; modules

Ralph Becket rafe at cs.mu.OZ.AU
Fri May 10 12:40:48 AEST 2002


Bob McKay, Thursday,  9 May 2002:
> 
> So on to the next challenge, which is to plug a newly generated
> subtree in a specific (randomly generated) position (the numeric
> position in an infix traversal) in an existing tree (I'm being
> careless with my phrasing, but you know what I mean):
> 
> insert:: Exp,int,Exp -> Exp

If I understand you correctly, you want to (a) define a mapping from
the integers to nodes in a tree and (b) have a function that will
replace a node with a given index with a different subtree.

To do this, you're going to need a function that will allow you to
replace a given child of a node.  This will have to be specific to
each tree type.

It may well be easier to use a generic tree type rather than try to
generalise over them by passing higher order functions.  One candidate
type is

	:- type tree(T) ---> tree(T, list(tree(T))).

One way to index the nodes is in depth-first traversal order.  If you
annotate each subtree with its size, the code is simplified (you can
avoid the annotation if you don't mind more expensive indexing):

	:- type tree(T) --->
		tree(T, int, trees(T)).

	:- type trees(T) == list(tree(T)).

	:- func sz(tree(T)) = int.

	sz(tree(_, Sz, _)) = Sz.

Now we can write 

	:- func replace(tree(T), int, tree(T)) = tree(T).

	replace(tree(X, _, Ts0), N, R) = T :-
		( if N =< 0 then
			T  = R
		  else
		  	Ts = replace_child(Ts0, N - 1, R),
			Sz = sum(map(sz, Ts)),
			T  = tree(X, Sz, Ts)
		).

	:- func replace_child(trees(T), int, tree(T)) = trees(T).

	replace_child([],       _, _) = [].

	replace_child([T | Ts], N, R) =
		( if N < sz(T) then [replace(T, N, R) | Ts]
		               else [T | replace_child(Ts, N - sz(T), R)]
		).

The transformation from this code to generic stuff using higher order
functions to extract and replace child nodes is straightforward, but
not pretty.

(If you want to squeeze a little more efficiency out of the above,
change replace_child/3 into a predicate that computes not only the
replacement children, but also the change in size due to the
replacement.  You can then avoid the sum(map(sz, Ts)) in replace/3.
Although it may well not be worth it.)

- Ralph
--------------------------------------------------------------------------
mercury-users mailing list
post:  mercury-users at cs.mu.oz.au
administrative address: owner-mercury-users at cs.mu.oz.au
unsubscribe: Address: mercury-users-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-users-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the users mailing list