重新安排variable_names
如何以符合标准的方式avs_term_rearranged(AVs, T, AVsR)
具有给定的AVs
和T
avs_term_rearranged(AVs, T, AVsR)
,使得AVsR
是AVs
的排列,其中排列顺序与它们的variables相同的元素在T
以从左到右的顺序出现。
AVs
是A = V
forms的元素的列表,其中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
如果
X
和Y
是不相同的variables,则X
term_presentedY
应该是实现相关的,除了在创build一个sorting列表(7.1.6.5,8.10.3.1j)期间,sorting应保持不变。注 – 如果
X
和Y
都是匿名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).