library(samefunctor)This library package is supplied to solve the following problem: often you
could
write code that works more than one way around except that this requires
calling functor/3
twice, and one of the calls must therefore precede the other. For
example,
reverse_terms(Term1, Term2) :-
functor(Term1, F, N), % ***
functor(Term2, F, N), % ***
reverse_terms(N, 1, Term1, Term2).
reverse_terms(0, _, _, _) :- !.
reverse_terms(Z, A, Term1, Term2) :-
arg(Z, Term1, Arg),
arg(A, Term2, Arg),
Y is Z-1, B is A+1,
reverse_terms(Y, B, Term1, Term2).
As written, this can only be used to find Term2 given Term1.
If you swapped the two *** lines, you could find Term1 given
Term2, but then could not find Term2 given Term1. You can make a
bidirectional version of reverse_terms/2 by using the
predicate same_functor/3 in place of the *** lines:
reverse_terms(Term1, Term2) :-
same_functor(Term1, Term2, N), % ***
reverse_terms(N, 1, Term1, Term2).
library(samefunctor) defines the following predicates:
same_functor(?Term1, ?Term2, ?Symbol, ?Arity)
same_functor(T1, T2, F, N) if
functor(T1, F, N) and
functor(T2, F, N) are both true.
Either Term1, or Term2, or both Symbol and Arity
should be instantiated. This is the most general variant.
same_functor(?Term1, ?Term2, ?Arity)
same_functor/3 is appropriate and the greater
generality of same_functor/4 is not needed.
same_functor(?Term1, ?Term2)
Note that same_functor/4 has the same argument order as
functor/3 except that it has two "term" arguments at the front.
Whenever a predicate's arguments include a functor specification expressed as
two arguments, the function symbol and its arity,
those two arguments should always
be adjacent, with the function symbol first and the arity immediately
following. functor/3 and same_functor/4 obey this rule.