Debugging, Testing & Documentation
Tracer commands: c/Enter (creep), s (skip), l (leap), r (retry), f (fail), a (abort), n (nodebug), g (goals stack), h (help).
26.1 Tracing
Tracer commands: c/Enter (creep), s (skip), l (leap), r (retry), f (fail), a (abort), n (nodebug), g (goals stack), h (help).
?- trace. % start tracer for the next goal
?- trace, my_pred(X).
?- gtrace. % graphical tracer (SWI)
?- spy(my_pred/2). % set a spy point (breakpoint)
?- nospy(my_pred/2).
?- debug. % debug mode: stop only at spy points
?- nodebug.
?- leash(-all). % don't stop at ports, just print
?- visible(+all).26.2 Debug messages & assertions
:- use_module(library(debug)).
:- debug(parser). % enable topic
parse(X) :- debug(parser, "parsing ~w", [X]), ...
check(X) :- assertion(integer(X)). % raises if false26.3 Common errors & warnings
Singleton variables: a variable used only once → probably a typo (use _X if intended).
Clauses not together: discontiguous predicate warning.
Unknown procedure: misspelled predicate or wrong arity.
Arguments are not sufficiently instantiated: calling is, comparison or a built-in with unbound variables.
Infinite loops / stack overflows: left recursion, missing base cases, cyclic data.
?- check. lists undefined predicates and other problems in loaded code.
26.4 Unit testing with plunit
Options: true(Cond), all(Template == List), set(...), fail, throws(E), nondet, blocked(Reason), fixme(Reason), condition(G), forall(Gen).
Property-based testing: library(quickcheck) pack; coverage: show_coverage/1.
:- begin_tests(lists_ext).
test(reverse) :- reverse([1, 2, 3], [3, 2, 1]).
test(member, [nondet]) :- member(b, [a, b, c]).
test(append_split, all(X == [[], [1], [1, 2]])) :- append(X, _, [1, 2]).
test(fails, [fail]) :- member(z, [a, b]).
test(error, [throws(error(type_error(_, _), _))]) :- atom_length(f(x), _).
test(eq, [true(R =:= 6)]) :- sum_list([1, 2, 3], R).
test(setup, [setup(assertz(tmp(1))), cleanup(retractall(tmp(_)))]) :- tmp(1).
:- end_tests(lists_ext).
?- run_tests.
?- run_tests(lists_ext:reverse).26.5 Documentation with PlDoc
Mode indicators: + input (instantiated), - output (unbound), ? either, : meta, @ not further instantiated, ! mutable. Determinism: det, semidet, nondet, multi, failure, erroneous.
?- doc_server(4000). serves documentation in the browser; doc_save/2 generates HTML.
%! area(+Shape, -Area:float) is det.
%
% Computes the area of Shape, which is circle(R) or rect(W, H).
%
% @arg Shape the geometric shape
% @throws type_error if Shape is unknown
area(circle(R), A) :- A is pi * R ** 2.🧪 Part II Exercises
Rewrite max/3 without a red cut, using if-then-else.
Define operators so that john is_father_of mary. is a valid fact; query it.
Write count_functor(F/A, Term, N) counting occurrences of a functor in any term.
Using setof/3, list all distinct grandparents in the family database, sorted.
Write a DCG that parses dates like "2026-10-25" into date(Y, M, D) and validates month/day ranges.
Write a DCG for simple arithmetic that builds an AST (plus/2, times/2, num/1), then an evaluator.
Read a CSV file (library(csv)) and compute the average of a numeric column.
Implement a word-frequency counter for a text file using split_string/4 and library(pairs).
Write quicksort/2 with difference lists (no append/3).
Organize exercises 5–6 into a module with exports, PlDoc comments, and a plunit test suite.