Control

Prefer separate clauses over ; for readability.

12.1 Conjunction, disjunction

Prefer separate clauses over ; for readability.

a :- b, c.          % b AND c
a :- b ; c.         % b OR c
a :- (b, c ; d).    % (b AND c) OR d

12.2 If-then-else

(Cond -> Then ; Else) commits to the first solution of Cond. Without ; Else, the construct fails if Cond fails.

*-> (soft-cut, SWI): (Cond *-> Then ; Else) backtracks into all solutions of Cond.

if_/3 from library(reif) gives a pure, monotonic if-then-else (§27).

classify(N, Type) :-
    (   N < 0 -> Type = negative
    ;   N =:= 0 -> Type = zero
    ;   Type = positive
    ).

12.3 Negation as failure: \+

\+ G succeeds if G cannot be proven. It is not logical negation:

Rule: only call \+ on sufficiently instantiated goals (ground is safest). Use dif/2 for sound disequality.

not_member(X, L) :- \+ member(X, L).

bachelor(X) :- male(X), \+ married(X).
?- \+ X = a.          % false — because X = a is provable
?- X = b, \+ X = a.   % true

12.4 true, fail, false, repeat

true.                % always succeeds
fail. false.         % always fail
repeat.              % succeeds infinitely on backtracking

print_all :- member(X, [1, 2, 3]), writeln(X), fail.   % failure-driven loop
print_all.

read_loop :- repeat, read(T), ( T == end_of_file -> ! ; process(T), fail ).

12.5 call, once, ignore, forall

call(G)                  % call a goal stored in a variable
call(format, "~w~n", [x])  % call/N adds arguments
once(G)                  % first solution only (= (G -> true))
ignore(G)                % call G, succeed anyway
forall(Cond, Action)     % for every solution of Cond, Action succeeds (= \+ (Cond, \+ Action))
?- forall(member(X, [1, 2, 3]), X > 0).        % true
?- forall(member(X, [a, b]), format("~w~n", [X])).