instantiation_error() if Term is unbound
and Name/Arity is insufficiently instantiated.
SWI-Prolog also supports terms with arity 0, as in a()
(see
section 5). Such terms
must be processed using
functor/4
or compound_name_arity/3.
The predicate functor/3
and
=../2 raise a domain_error
when faced with these terms. Without this precaution a round trip
of a term with arity 0 over functor/3
would create an atom.
a(), see section
5). Type is one of atom,
compound, callable or atomic. Type
must be instantiated if Name is an atom and Arity
is 0 (zero). In other cases Type may be a variable. This
predicate is true if Term (either initially or after having
been created from Name and Type) and Type
are related as below
compound or callable.
If
Type is unbound is is unified with compound.
atom
or callable. If Type is unbound is is unified
with
atom.
atomic.
This predicate provides a safe round trip for zero-arity compounds and atoms. It can also be used as a variant of functor/3 that only processes compound or callable terms. See also compound/1, callable/1 and compound_name_arity/3.
domain_error(not_less_than_zero, Arg) if Arg
< 0.?- foo(hello, X) =.. List. List = [foo, hello, X] ?- Term =.. [baz, foo(1)]. Term = baz(foo(1))
SWI-Prolog also supports terms with arity 0, as in a()
(see
section 5). Such terms
must be processed using
compound_name_arguments/3.
This predicate raises a domain error as shown below. See also functor/3.
?- a() =.. L. ERROR: Domain error: `compound_non_zero_arity' expected, found `a()'
name()). See also compound_name_arguments/3.
See also functor/4.$VAR(N),
where N is the number of the variable. Counting starts at
Start. End is unified with the number that should
be given to the next variable.bugOnly tagged
integers are supported (see the Prolog flag max_tagged_integer).
This suffices to count all variables that can appear in the largest term
that can be represented, but does not support arbitrary large integer
values for Start. On overflow, a representation_error(tagged_integer)
exception is raised. The example below illustrates this.
Note that the toplevel prints '$VAR'(0) as A due
to the
numbervars(true) option used to print answers.
?- Term = f(X,Y,X),
numbervars(Term, 0, End, [singleton(true)]),
write_canonical(Term), nl.
f('$VAR'(0),'$VAR'('_'),'$VAR'(0))
Term = f(A, _, A),
X = A,
Y = B,
End = 2.
See also the numbervars option to write_term/3
and numbervars/4.
$VAR.skip, which causes numbervars/3
to ignore the attributed variable, bind which causes it to
treat it as a normal variable and assign the next '$VAR'(N)
term to it, or (default)
error which raises a type_error exception.118This
behaviour was decided after a long discussion between David Reitter,
Richard O'Keefe, Bart Demoen and Tom Schrijvers.true (default false), numbervars/4
does singleton detection. Singleton variables are unified with '$VAR'('_'),
causing them to be printed as _ by write_term/2
using the numbervars option. This option is exploited by portray_clause/2
and write_canonical/2.bugCurrently
this option is ignored for cyclic terms.
'$VAR'(X)
and opens the path for replacing this valid Prolog term by an internal
representation that has no textual equivalent.library(backcomp). The variables in List
are ordered in order of appearance traversing Term
depth-first and left-to-right. See also
term_variables/3
and nonground/2.
For example:
?- term_variables(a(X, b(Y, X), Z), L). L = [X, Y, Z].
representation_error
is raised. Note that, if a variable appears in a shared
subterm, it is not considered singleton. Thus,
A is not a singleton in the example below. See also
the singleton option of numbervars/4.
?- S = a(A), term_singletons(t(S,S), L). L = [].
1 is_most_general_term(1)false 2 is_most_general_term(p)true 3 is_most_general_term(p(_))true 4 is_most_general_term(p(_,a))false 5 is_most_general_term(p(X,X))false 6 is_most_general_term([])true 7 is_most_general_term([_|_])false 8 is_most_general_term([_,_])true 9 is_most_general_term([X,X])false
?- copy_term([X], q(X,Y), Vars, Term). Vars = [_A], Term = q(_A, Y).
Note that if VarsIn and In do not share any
variables,
Out is equivalent to In and VarsOut is
a copy (as copy_term/2)
of VarsIn. If In does not contain any variables
not in VarsIn the result is the same as
copy_term(VarsIn-In, VarsOut-Out).
Var = Value giving those subterms. After
unifying all substitutions in Substitution, Term ==
Skeleton.
Term may be cyclic. The cycles come back through the substitutions, so Skeleton itself is acyclic:
?- X = a(X), term_factorized(b(X,X), Y, S). Y = b(_A, _A), S = [_A=a(_A)].
Subterms are the same when they are ==/2. For a rational tree that means when they denote the same infinite tree, so Term is factorized as far as it can be:
?- X = f(X), Y = f(f(Y)), term_factorized(p(X,Y), S, B). S = p(_A, _A), B = [_A=f(_A)].
The substitutions come in a canonical order, which makes
Skeleton-Substitution a key for =@=/2.
true (default), subterms are the same when they are
==/2, as above. If false,
only cells that are literally the same cell are shared. That is the
sharing a term has in memory rather than the sharing implied by what it
means, and it is what
write_term/2
uses for the cycles option:
?- term_factorized(f(g(a),g(a)), S, B, [minimal(false)]). S = f(g(a), g(a)), B = []. ?- term_factorized(f(g(a),g(a)), S, B, [minimal(true)]). S = f(_A, _A), B = [_A=g(a)].
true (default), '$VAR'(N) is
left alone rather than taken apart, as it stands for a variable. See numbervars/3.
Minimal == Term and Minimal uses the
least possible number of compound cells. Subterms denoting the same tree
are shared, so a cyclic term or one with repeated subterms comes back
smaller, while one with neither comes back unchanged:
?- X = f(g(a),g(a)), term_minimal(X, M), M == X. true.
Because ==/2 on rational
trees is bisimulation, there is no smaller term that is still ==/2
to Term. A term of
N cells can denote a tree with 2^N nodes, or an
infinite one, so this can be a large saving: a cyclic term of a million
cells all denoting h(h(h(...))) minimises to one cell.
After term_minimal/2, operations that walk the term graph, such as ==/2, copy_term/2, assertz/1 and term_hash/2, have less to walk.
See also term_automaton/2, which writes the term graph out as an explicit automaton, and automaton_minimal/2, which minimises one.
Automaton is a compound whose argument I is the colour of state I, and state 1 is the start state. An argument that is a compound gives the state one successor per argument of that compound, and the argument is the number of the state the successor goes to. An argument that is not a compound makes the state a sink holding that value. So a leaf is a state rather than an argument, which is why nothing in an argument position is ever anything but a state number:
?- term_automaton(f(g(a),g(a)), A). A = automaton(f(2, 3), g(4), g(4), a).
The translation is faithful in both directions: one state per physically distinct compound cell of Term and one per distinct leaf, sharing what Term already shares and collapsing nothing. Term may be cyclic, and so may Automaton:
?- X = f(X), term_automaton(X, A). A = automaton(f(1)).
The functor name of Automaton is not looked at when it is
read; like arg/3,
only the arity matters. The name used when it is written is always automaton.
Note that the value of a sink can never be a compound, so a state label
that is a compound has to be taken apart into states of its own.
?- automaton_minimal(automaton(f(2,3), g(1), g(1), a, h(4)), M). M = automaton(f(2, 2), g(1)).
State 1 of Minimal is still the start state, and the states are numbered depth first from it, so the answer does not depend on the order Automaton happened to be written in. Two automata therefore denote the same tree exactly when their minimal forms are =@=/2, and automaton_minimal/2 is idempotent.
Together with term_automaton/2 this is term_minimal/2:
term_minimal(T, M) :-
term_automaton(T, A),
automaton_minimal(A, A1),
term_automaton(M, A1).
The transition relation is a function: a state has exactly one successor per argument position. Nondeterministic transition systems are not supported.
?- automaton_minimal(automaton(f(2,3), g(1), g(1), a), M, Map). M = automaton(f(2, 2), g(1)), Map = map(1, 2, 2, 0).
Prolog is not able to modify instantiated parts of a term. Lacking that capability makes the language much safer, but unfortunately there are problems that suffer severely in terms of time and/or memory usage. Always try hard to avoid the use of these primitives, but they can be a good alternative to using dynamic predicates. See also section 4.33, discussing the use of global variables.
This predicate may be used for destructive assignment to terms, using them as an extra-logical storage bin. Always try hard to avoid the use of setarg/3 as it is not supported by many Prolog systems and one has to be very careful about unexpected copying as well as unexpected noncopying of terms. A good practice to improve somewhat on this situation is to make sure that terms whose arguments are subject to setarg/3 have one unused and unshared variable in addition to the used arguments. This variable avoids unwanted sharing in, e.g., copy_term/2, and causes the term to be considered as non-ground. An alternative is to use put_attr/3 to attach information to attributed variables (see section 8.1).
setarg(A,T,V,false), removing
the type restriction on Value. Below is an example for
counting the number of solutions of a goal. Note that this
implementation is thread-safe, reentrant and capable of handling
exceptions. Realising these features with a traditional implementation
based on assert/retract or flag/3
is much more complicated.
:- meta_predicate
succeeds_n_times(0, -).
succeeds_n_times(Goal, Times) :-
Counter = counter(0),
( Goal,
arg(1, Counter, N0),
N is N0 + 1,
nb_setarg(1, Counter, N),
fail
; arg(1, Counter, Times)
).
See also nb_linkarg/3 and foldall/4.