Performance

Prolog indexes clauses on the first argument (SWI uses JIT multi-argument indexing).

37.1 First-argument indexing

Prolog indexes clauses on the first argument (SWI uses JIT multi-argument indexing). Distinct functors in the first argument avoid choice points:

Put the most discriminating argument first. Use jiti_list/1 (SWI) to inspect indexes.

% Good: indexing on [] vs [_|_] → deterministic
len([], 0).
len([_|T], N) :- len(T, N0), N is N0 + 1.

37.2 Last-call optimization & determinism

Make recursive calls last; avoid leaving choice points (use indexing, ->, or cuts).

Check with ?- Goal. — if the top level prints true ; instead of true., a choice point remains.

deterministic/1, $/1, det/1 declarations (SWI 8.5+) assert determinism.

37.3 Avoid common inefficiencies

append/3 in loops (O(n²)) → accumulators or difference lists.

Naive reverse → accumulator reverse.

Repeated length/2 → track counts.

findall + length to count → aggregate_all(count, ...).

assert/retract for loop state → arguments.

Use memberchk/2 instead of member/2 for membership tests.

Use assoc/rbtrees/dicts instead of lists for large lookups.

Use tabling for overlapping subproblems.

Order goals: cheap & most constraining first ("fail early").

Use msort/2/sort/4 and keysort/2 (fast C implementations).

37.4 Profiling & measuring

Increase stacks: swipl --stack-limit=4g. Garbage collection is automatic (garbage_collect/0).

?- time(nrev(1000)).                    % inferences, CPU time, LIPS
?- profile(my_goal).                    % graphical/text profiler (SWI)
?- statistics(runtime, [T, _]).
?- call_time(Goal, Dict).               % library(statistics)

37.5 Compilation

SWI compiles clauses to a virtual machine (not WAM exactly); qsave_program/2 creates saved states.

GNU Prolog compiles to native code; SICStus has native JIT on some platforms.

library(apply_macros), :- set_prolog_flag(optimise, true) for arithmetic compilation.