freeze for more than one variable

517 views Asked by At

I tried to write a predicate that takes a list and converts it to a balanced tree. My code looks as follows:

/* make_tree(list, tree)
 *
 *    list: list with the elements of the tree in prefix order
 *    tree: balanced tree of the elements in the list
 * 
 */
make_tree([], empty).
make_tree([H|T], node(L, R, H)):-
    split_half(T, T1, T2),
    make_tree(T1, L),
    make_tree(T2, R).

/* split_half(list, first, second)
 * 
 *    list: list with n elements
 *    first: list with first (n // 2) elements
 *    second: list with last (n - n // 2) elements
 *
 */
split_half(L, L1, L2):-
   split_half(L, L, L1, L2).

split_half(L, [], [], L):- !.
split_half(L, [_], [], L):- !.
split_half([H|T], [_,_|Acc], [H|L1], L2):-
   split_half(T, Acc, L1, L2).

and this works when called like:

?- make_tree([1,2,3], Tree).
Tree = node(node(empty, empty, 2), node(empty, empty, 3), 1).

but it doesn't work when calling it in the other way, like:

?- make_tree(L, node(node(empty, empty, 2), node(empty, empty, 3), 1)).
false.

It's not really necessary, but I accepted the challenge anyway to make it work both ways. I wanted to solve this by using freeze/2 on split, like freeze(T2, split(T, T1, T2)) and this makes that ?- make_tree(L, node(node(empty, empty, 2), node(empty, empty, 3), 1)). works, but the original idea doesn't anymore. So actually what I'm looking for is some kind of freeze/2 that can do something like freeze((T;T2), split(T, T1, T2)). Does anybody know how to solve this issue?

Thanks in advance

2

There are 2 answers

5
repeat On BEST ANSWER

Most likely you are looking for when/2. It is offered by both SICStus Prolog (manual page) and SWI-Prolog (manual page).

Sample use:

myfreeze1(V,Goal) :-
   when(nonvar(V),Goal).

myfreeze2(V1,V2,Goal) :-
   when((nonvar(V1);nonvar(V2)),Goal).
3
false On

Here is a method without using coroutining. The idea is to establish first a relation between the tree and the number of its elements which is represented by a list. Note that we first do not look at concrete elements (_) since we do not know their order yet. With the number of elements being fixed, we can proceed as before but without the cuts.

list_tree(Xs, Tree) :-
   phrase(tree_els(Tree), Xs),
   make_tree(Xs, Tree).

tree_els(empty) -->
   [].
tree_els(node(L, R, _)) -->
   [_],
   tree_els(L),
   tree_els(R).

This version might profit from coroutining for performance reasons. After all tree_els/1 will succeed for all possible trees be they balanced or not.