冻结多个变量

时间:2015-06-08 12:19:58

标签: prolog prolog-coroutining

我尝试编写一个带有列表并将其转换为平衡树的谓词。我的代码如下:

/* 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).

,这在调用时起作用:

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

但是在以其他方式调用它时它不起作用,例如:

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

这不是必要的,但无论如何我接受了挑战,使其双向运作。我希望在freeze/2上使用split解决此问题,例如freeze(T2, split(T, T1, T2)),这会使?- make_tree(L, node(node(empty, empty, 2), node(empty, empty, 3), 1)).有效,但最初的想法不再存在。所以实际上我正在寻找的是某种freeze/2可以做freeze((T;T2), split(T, T1, T2))之类的事情。有人知道如何解决这个问题吗?

提前致谢

2 个答案:

答案 0 :(得分:3)

您很可能正在寻找when/2。它由SICStus Prolog(manual page)和SWI-Prolog(manual page)提供。

样品使用:

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

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

答案 1 :(得分:3)

这是一种不使用coroutining的方法。我们的想法是首先建立树与其元素的 number 之间的关系,该关系由列表表示。请注意,我们首先不查看具体元素(_),因为我们还不知道它们的顺序。随着元素数量的固定,我们可以像以前一样继续进行,但没有削减。

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).

由于性能原因,此版本可能会从coroutining中获益。在所有可能的树都成功tree_els/1之后,它们是否平衡。