Part of Prolog builtins are related to structure (functors) inspection:
variables bound to structures can be accessed to find out the functor
name, its arity, a given argument, etc. The two basic predicates for
doing that are `functor/3` and `arg/3`.

`functor(F, N, A)` succeeds when `F` is a complex
structure whose arity is `N` and whose arity is `A`. It
can be used to build new functors with fresh variables, or to obtain
the name and arity of already built functors:

?- X = corn(loki, K, straight), functor(X, N, A). A = 3, N = corn, X = corn(loki,K,straight) yes ?- functor(X, steam, 10). X = steam(_,_,_,_,_,_,_,_,_,_)

`arg(F, N, Arg)` succeeds when `Arg` is the
`N`-th argument of functor `F`. Arguments start
numbering at 1:

?- arg(1, corn(loki, K, straight), A). A = loki ? yes ?- arg(2, corn(loki, K, straight), A). K = A ? yes ?- arg(0, corn(loki, K, straight), A). no ?- functor(X, steam, 10), arg(8, X, engine). X = steam(_,_,_,_,_,_,_,engine,_,_) ? yes

subterm(Term, Term). subterm(Sub,Term):- functor(Term,F,N), subterm(N,Sub,Term). subterm(N,Sub,Term):- arg(N,Term,Arg), % N > 0 subterm(Sub,Arg). subterm(N,Sub,Term):- N>1, N1 is N-1, subterm(N1,Sub,Term).

`Term` is traversed, element by element. If an
argument of `Term` unifies with
`SubTerm`, then `SubTerm` is
already contained in `Term` (possibly after
unifying one of its variables). Otherwise, the argument at hand is
recursively traversed:

?- subterm(f(g), h(11, [oc, f(g)], loc)). yes ?- subterm(f(T), h(11, [oc, f(g)], loc)). T = g ? ; no ?- subterm(f(T), h(11, [oc, f(g)], I)). I = f(T) ? ; T = g ? ; no

Another example of the application of structure-inspecting primitives
is to use them to implement arrays. Arrays themselves are not
available as a Prolog datatype, with associated operations, but they
are easily simulated with structures. Any element of a structure can
be accessed using its position. The name of the functor does not
matter, actually. As an example, we will implement the predicate
`add_arrays/3` which will add the arrays passed in the first
and second argument, and will leave the result in the third argument.
The functor name we have chosen for the arrays is `array/3`:

add_arrays(A1,A2,A3):- functor(A1,array,N), %% Equal length functor(A2,array,N), functor(A3,array,N), add_elements(N,A1,A2,A3). add_elements(0,_A1,_A2,_A3). add_elements(I,A1,A2,A3):- arg(I,A1,X1), %% I > 0 arg(I,A2,X2), arg(I,A3,X3), X3 is X1 + X2, I1 is I - 1, add_elements(I1,A1,A2,A3).

The code first checks that the three arguments have the same functor name and arity; then the arrays are traversed from the end to the beginning (to use only one index, stopping at 0), and the corresponding elements in the arrays are added.

**Note:** some Prolog (and CLP) systems have a maximum fixed
arity. Other implementation schemes (lists, for example, as done in
the CLP arrays multiplication in Section 3.17.1)
should be used for simulating larger arrays.

would represent the matrix

I.e., its behavior should be as follows:

?- add_matrices(mat(mat(1, 2), mat(4, 3)), mat(mat(7, -2), mat(10, 4)), X). X = mat(mat(8, 0), mat(14, 7))

It should fail if the matrices to add do not have the same dimensions or the proper functor name. For simplicity, a number itself can be considered a matrix, so the query and answer

?- add_matrices(7, 4, X). X = 11

are both legal.

There is also a utility predicate which converts (in a quite bizarre
way) lists into structures and vice versa. The ``conversion'' is done
as follows: the name of the structure is the first atom in the list,
and the rest of elements of the list are the arguments of the
structure. It is called *univ*, and its predicate name is
`=..`, which is also defined as an infix operator:

?- date(9,february,1947) =.. L. L = [date,9,february,1947]. ?- X =.. [+,a,b]. X = a + b.

This builtin should be avoided unless really necessary: it is expensive in time and memory, and most time using it is a last resort for badly designed data structures and/or programs.

1998-12-03