重新安排variable_names

如何以符合标准的方式avs_term_rearranged(AVs, T, AVsR)具有给定的AVsT avs_term_rearranged(AVs, T, AVsR) ,使得AVsRAVs的排列,其中排列顺序与它们的variables相同的元素在T以从左到右的顺序出现。

AVsA = Vforms的元素的列表,其中A是指示variables名称如'X'的primefaces, V是相应的variables。 这样的列表由read_term/2,3和read-option variable_names/1 (7.10.3)生成。 另外,没有定义元素的精确顺序。

 | ?- read_term(T,[variable_names(AVs)]). A+B+A+_+C. AVs = ['A'=A,'B'=B,'C'=C] T = A+B+A+_+C 

T是一个包含AVs所有variables加上一些的术语。

请注意,在标准的一致性程序中,不能依赖于variables(7.2.1)的术语顺序:

7.2.1variables

如果XY是不相同的variables,则X term_presented Y应该是实现相关的,除了在创build一个sorting列表(7.1.6.5,8.10.3.1j)期间,sorting应保持不变。

注 – 如果XY都是匿名variables,那么它们就不是同一个术语(见6.1.2a)。

以8.4.3.4为例:

 sort([f(U),U,U,f(V),f(U),V],L). Succeeds, unifying L with [U,V,f(U),f(V)] or [V,U,f(V),f(U)]. [The solution is implementation dependent.] 

所以有两种可能的方式,第二sort/2将工作,甚至不能依靠的成功:

 sort([f(U),U,U,f(V),f(U),V],L), sort(L, K), L == K. 

举个例子:

 ?- avs_term_rearranged(['A'=A,'B'=B,'C'=C], A+C+F+B, AVsR). AVsR = ['A'=A,'C'=C,'B'=B]. 
 avs_term_rearranged(AVs, T, AVsR) :- term_variables(T, Vs), copy_term(Vs+AVs, Vs1+AVs1), bind_names(AVs1), build_vn_list(Vs, Vs1, AVsR). bind_names([]). bind_names([N=V|AVs]) :- N = V, bind_names(AVs). build_vn_list([], [], []). build_vn_list([V|Vs],[N|Ns],NVs) :- ( atom(N) -> NVs = [N=V|NVs1] ; var(N) -> NVs = NVs1 ), build_vn_list(Vs, Ns, NVs1). 

使用T上的term_variables/2来获得一个列表Xs其中包含所需顺序的variables。 然后按顺序build立一个包含AVs元素的列表。

 avs_term_rearranged(AVs, T, AVRs) :- term_variables(T, Xs), pick_in_order(AVs, Xs, AVRs). pick_in_order([], [], []). pick_in_order(AVs, [X|Xs], AVRs) :- ( pick(AVs, X, AV, AVs1) -> AVRs = [AV|AVRs1], pick_in_order(AVs1, Xs, AVRs1) ; pick_in_order(AVs, Xs, AVRs) ). pick([AV|AVs], X, AX, DAVs) :- (_=V) = AV, ( V==X -> AX = AV, DAVs = AVs ; DAVs = [AV|DAVs1], pick(AVs, X, AX, DAVs1) ). 

笔记:

  • 这是二次方,因为pick/4是线性的
  • term_variables/2并不是绝对必要的,你可以直接遍历T

我以前的答案有二次运行的复杂性。 如果这是一个问题,这是一个线性的select。 这有点棘手的原因是未绑定的variables不能用作散列等的键。

和以前一样,我们基本上重新排列列表AVs ,使得它的元素与列表Xs的variables(从term_variables/2获得)具有相同的顺序。 这里的新思想是首先计算需要的置换( APs )的(地面)描述,然后用这个描述构造AV的置换。

 avs_term_rearranged(AVs, T, AVRs) :- term_variables(T, Xs), copy_term(AVs-Xs, APs-Ps), ints(Ps, 0, N), functor(Array, a, N), distribute(AVs, APs, Array), gather(1, N, Array, AVRs). ints([], N, N). ints([I|Is], I0, N) :- I is I0+1, ints(Is, I, N). distribute([], [], _). distribute([AV|AVs], [_=P|APs], Array) :- nonvar(P), arg(P, Array, AV), distribute(AVs, APs, Array). gather(I, N, Array, AVRs) :- ( I > N -> AVRs = [] ; arg(I, Array, AV), I1 is I+1, ( var(AV) -> AVRs=AVRs1 ; AVRs = [AV|AVRs1] ), gather(I1, N, Array, AVRs1) ). 

这个版本很短,使用member/2 (来自Prolog序言)进行search。 它具有非常低的辅助内存消耗。 只有列表AVsR被创build。 没有创build临时堆术语(在当前实现上)。 它在AVs的长度上有二次开销。

 avs_term_rearranged(AVs, T, AVsR) :- term_variables(T, Vs), rearrange(Vs, AVs, AVsR). rearrange([], _, []). rearrange([V|Vs], AVs, AVsR0) :- ( member(AV, AVs), AV = (_=Var), V == Var -> AVsR0 = [AV|AVsR] ; AVsR0 = AVsR ), rearrange(Vs, AVs, AVsR). 

另一个方面是member(AV, AVs)目标本质上是非确定性的,即使只涉及相对较浅的非确定性,而@ jschimpf的(第一个)版本确实只为(;)/2创buildselect点if-then-else-implementation。 两个版本都没有留下任何select点。

这是一个更忠实地模拟@ jschimpf的想法的版本。 然而,这现在创build了堆中的辅助术语。

 rearrange_js([], _, []). rearrange_js([V|Vs], AVs0, AVsR0) :- ( select(AV, AVs0, AVs), AV = (_=Var), V == Var -> AVsR0 = [AV|AVsR] ; AVsR0 = AVsR, AVs0 = AVs ), rearrange_js(Vs, AVs, AVsR).