Checking Functors -- 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)
is true when Term1 and Term2 have the same principal functor, the function symbol being Symbol and the arity being Arity. In other words,
          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)
is true when Term1 and Term2 have the same principal functor, and Arity is their common arity. Either Term1 or Term2 should be instantiated, and the other arguments can then be found. Often, same_functor/3 is appropriate and the greater generality of same_functor/4 is not needed.
same_functor(?Term1, ?Term2)
is true when Term1 and Term2 have the same principal functor. Either Term1 or Term2 should be instantiated, and the other argument can then be found.

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.