fal*_*lse 47 prolog iso-prolog
如何在一个符合标准的方式写入avs_term_rearranged(AVs, T, AVsR)
与给定的AVs
和T
,使得AVsR
是的置换AVs
作为其变量发生在左到右的顺序与布置在相同的顺序中的元素T
.
AVs
是一个表单元素的列表,A = V
其中A
一个原子指定一个变量名称,'X'
并且V
是一个相应的变量.这些列表由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
Run Code Online (Sandbox Code Playgroud)
T
是一个包含所有变量AVs
加上更多的变量的术语.
请注意,在标准符合程序中,不能依赖变量的术语顺序(7.2.1):
7.2.1变量
如果
X
和Y
是不相同的变量,则X
term_precedesY
应依赖于实现,除了在创建排序列表(7.1.6.5,8.10.3.1 j)期间,排序应保持不变.注 - 如果
X
和Y
都是匿名变量,则它们不是相同的术语(见6.1.2 a).
以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.]
Run Code Online (Sandbox Code Playgroud)
因此,有两种可能的方法sort/2
可行,甚至不能依赖于以下方面的成功:
sort([f(U),U,U,f(V),f(U),V],L), sort(L, K), L == K.
Run Code Online (Sandbox Code Playgroud)
举个例子:
?- avs_term_rearranged(['A'=A,'B'=B,'C'=C], A+C+F+B, AVsR).
AVsR = ['A'=A,'C'=C,'B'=B].
Run Code Online (Sandbox Code Playgroud)
Per*_*ner 34
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).
Run Code Online (Sandbox Code Playgroud)
jsc*_*mpf 13
使用term_variables/2
on T
以获得具有Xs
所需顺序的变量的列表.然后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)
).
Run Code Online (Sandbox Code Playgroud)
笔记:
pick/4
是线性的term_variables/2
不是绝对必要的,你可以T
直接穿越jsc*_*mpf 12
我之前的回答有二次运行时复杂性.如果这是一个问题,这是一个线性的替代方案.这有点棘手的原因是未绑定的变量不能用作散列等的键.
和以前一样,我们基本上重新排列列表AVs
,使其元素与列表中的变量Xs
(从中获取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)
).
Run Code Online (Sandbox Code Playgroud)
此版本非常短,使用
member/2
(来自Prolog序言)进行搜索.它具有非常低的辅助内存消耗.仅AVsR
创建列表.不会创建临时堆项(在当前实现上).但是,它的长度有二次开销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).
Run Code Online (Sandbox Code Playgroud)
另一个方面是member(AV, AVs)
目标本质上是非确定性的,即使只涉及相对浅的非确定性,而@ jschimpf(第一)版本确实只为(;)/2
if-then-else实现创建一个选择点.两个版本都没有留下任何选择点.
这是一个更忠实地模拟@ jschimpf的想法的版本.但是,这会创建留在堆上的辅助术语.
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).
Run Code Online (Sandbox Code Playgroud)