How to write in a standard conforming manner avs_term_rearranged(AVs, T, AVsR)
with given AVs
and T
such that AVsR
is a permutation of AVs
with the elements arranged in same order as their variables occur in left-to-right order in T
.
AVs
is a list of elements of the form A = V
where A
is an atom designating a variable name like 'X'
and V
is a corresponding variable. Such lists are produced by read_term/2,3
with the read-option variable_names/1
(7.10.3). Additionally, the precise order of elements is not defined.
| ?- read_term(T,[variable_names(AVs)]).
A+B+A+_+C.
AVs = ['A'=A,'B'=B,'C'=C]
T = A+B+A+_+C
T
is a term that contains all variables of AVs
plus some more.
Note that in a standard conforming program one cannot rely on the term order for variables (7.2.1):
7.2.1 Variable
If
X
andY
are variables which are not identical thenX
term_precedesY
shall be implementation dependent except that during the creation of a sorted list (7.1.6.5, 8.10.3.1 j) the ordering shall remain constant.NOTE — If
X
andY
are both anonymous variables then they are not identical terms (see 6.1.2 a).
Consider as an example from 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.]
So there are two possible ways how sort/2
will work, and one cannot even rely on the success of:
sort([f(U),U,U,f(V),f(U),V],L), sort(L, K), L == K.
As an example:
?- avs_term_rearranged(['A'=A,'B'=B,'C'=C], A+C+F+B, AVsR).
AVsR = ['A'=A,'C'=C,'B'=B].
My previous answer had quadratic runtime complexity. If that's a problem, here is a linear alternative. The reason this is a bit tricky is that unbound variables cannot be used as keys for hashing etc.
As before, we basically rearrange the list
AVs
such that its elements have the same order as the variables in the listXs
(obtained fromterm_variables/2
). The new idea here is to first compute a (ground) description of the required permutation (APs
), and then construct the permutation ofAV
using this description.This version is very short, using
member/2
(from the Prolog prologue) for the search. It has very low auxiliary memory consumption. Only the listAVsR
is created. No temporary heap-terms are created (on current implementations). It has quadratic overhead in the length ofAVs
, though.Another aspect is that the
member(AV, AVs)
goal is inherently non-deterministic, even if only relatively shallow non-determinism is involved, whereas @jschimpf's (first) version does create a choice point only for the(;)/2
of the if-then-else-implementation. Both versions do not leave any choice points behind.Here is a version more faithfully simulating @jschimpf's idea. This, however, now creates auxiliary terms that are left on the heap.
Use
term_variables/2
onT
to obtain a listXs
with variables in the desired order. Then build a list with the elements ofAVs
, but in that order.Notes:
pick/4
is linearterm_variables/2
is not strictly necessary, you could traverseT
directly