Purity, Monotonicity & Declarative Style
A pure Prolog program uses only unification, conjunction, disjunction, and clause selection (plus pure constraints like dif/2 and CLP).
27.1 The pure core
A pure Prolog program uses only unification, conjunction, disjunction, and clause selection (plus pure constraints like dif/2 and CLP). Pure programs are:
Monotonic: adding a clause can only add solutions; generalizing a query never removes solutions.
Relational: work in all directions (append/3, length/2).
Declaratively debuggable: you can reason about meaning by removing goals ("generalization") or clauses.
Impure features (!, \+, var/1, assert, is/2, side effects) are sometimes necessary but break these properties.
27.2 Examples of impurity problems
?- X = 1, \+ X = 2. % true
?- \+ X = 2, X = 1. % false — order matters (non-monotonic)
?- dif(X, 2), X = 1. % true
?- X = 1, dif(X, 2). % true — dif/2 is order-independent27.3 Pure alternatives
\=, \==, \+ X = Y CLP(FD) #=, #< (C -> T; E) if_/3 with reified predicates (library(reif)) memberd_t/3, member/2 + dif (no pure equivalent; use carefully) clause indexing via distinct functors, if_/3
:- use_module(library(reif)). % pack in SWI; built into Scryer
list_without([], _, []).
list_without([X|Xs], E, Ys0) :-
if_(X = E, Ys0 = Ys, Ys0 = [X|Ys]),
list_without(Xs, E, Ys).27.4 Writing general predicates
Name predicates as relations: list_length/2 rather than get_length/2.
Test with the most general query: ?- list_length(L, N).
Ensure termination conditions: ?- Goal, false. should terminate (universal termination).
Use length(L, _) to fairly enumerate list lengths.
27.5 Declarative debugging: failure slices
Insert false into a clause body to isolate non-termination: if a "failure slice" (program with goals replaced by false) doesn't terminate, neither does the full program — you must fix the remaining visible part.