Avoids running goals to produce output that is only relevant while debugging. Includes pre-canned, often used calls that print informative messages for common debugging tasks.
See the main predicate's documenation, debug_call/4, for more details.
See file examples/exo.pl for a full pallette of examples.
?- debug(ex).
?- debug_call(ex, length, list1/[x,y,z]).
% Length for list, list1: 3
?- debug_call(ex, length, [list1,list2]/[[x,y,z],[a,b,c]], prefix('Some prefix')).
% Some prefix lengths for lists, list1: 3, list2: 3
?- debug_call(ex, dims, [m1,m2]/[[a(x),a(y),a(z)],[xy(a,b),xy(c,d),xy(e,f)]]).
% Dimensions for matrices, (m1) nR: 3, nC: 1. (m2) nR: 3, nC: 2.
?- debug_call(ex, enum, testo/[a,b,c]).
% Starting enumeration of list: testo
% 1.a
% 2.b
% 3.c
% Ended enumeration of list: testo
true.
?- debug_call(ex, enum, testo/[a,b,c,d,e], depth(3)).
% Starting enumeration of list: testo
% 1.a
% 2.b
% 3.c
% ... + 2 other elements
% Ended enumeration of list: testo
?- debug_call(ex, info, 'My message is ~w.'/long).
% My message is long.
true.
% message above is printed in informational colour
?- debuc(ex, wrote, loc(file,csv)).
% Could not locate wrote on file specified by: file, and extensions: csv
?- csv_write_file('file.csv', []).
?- debuc(ex, version, debug_call).
% Using debug_call_version, at version: 2:1:1 (published on: date(2025,12,6)).
?- debuc(ex, wrote, loc(file,csv)).
% Wrote on file: 'file.csv'
?- debuc(ex, task(stop), 'write on file').
At 15:44:1 on 2nd of Jul 2024 finished task: write on file.
?- debuc(ex, task(stop), 'talking ~w', [farg(point)]).
% At 13:58:50 on 6th of Dec 2025 stop task: talking point
?- assert((simple_mess(KVs,Mess,Args):- KVs =[a=A,b=B], atom_concat(A,B,Mess), Args=[])).
?- debuc(ex, simple_mess([a=1,b=2])).
% 12
true.
This library avoids the messy way in which package(debug) deals with variable debug topics.
That is, their term expansion and subsequent pattern matching mishandles goals of the form
debugging/1 and debug/3 that have an unbound variable in the 1st argument.
debug_calls uses dynamic =.. .
?- debug_call_version( -V, -D ). V = 2:2:0, D = date(2025,12,8).
If Goal with arity +2 is available call that instead of Goal with extra arguments Mess and Args
that will be passed to debug/3. If the goal (original or +2) fail, nothing is printed by
debug_call and the debug_call(T,G) itself succeeds.
?- goal( Goal, Mess, Args ).
Examples
?- debug(ex) ?- assert((simple_mess(KVs,Mess,Args):- KVs =[a=A,b=B], atom_concat(A,B,Mess), Args=[])). ?- debug_call(ex, simple_mess([a=1,b=2])). 12
lib(debug) does not create a record by inspecting the term (via expansion).
Particularly useful in sending uninstantiated Topics.
lib(debug) does not create a record by inspecting the term (via expansion).
Particularly useful in sending uninstantiated Topics.
debugging(Topic) succeeds. Else, it is false.
Similar to debugging/2, but does not fail for undefined Topic.
?- debug( something ). true. ?- debugging_status( something, Some ). Some = true. ?- debugging_status( some_else, Else ). Else = false.
?- nodebug( chained ). true. ?- debug( testo ). Warning: testo: no matching debug topic (yet) true. ?- debug( chained, 'debugs chains 1', [] ). true. ?- debug_chain( testo, chained, Prior ). Prior = false. ?- debug( chained, 'debugs chains 2', [] ). % debugs chains 2 true. ?- Prior = false, debug_set( Prior, chained ). Prior = false. ?- debug( chained, 'debugs chains 3', [] ). true
options(debug(true),Opts), with Restore
being instantiated to a term that can be used to restore the
original debug state of Topic (see options_restore/2). If options(debug(false),Opts)
then Topic is stopped from being debugged (Restore still holds the
correct term for restoring debugging state for topic to precall status).
?- assert( ( on_t(I,Topic) :- (debugging(Topic) -> write(I-y(Topic)) ; write(I-n(Topic))), nl ) ). ?- T = options, debug(T), on_t(1,T), debug_topic(T,[debug(false)],R), on_t(2,T), debug_set(R,T), on_t(3,T). 1-y(options) 2-n(options) 3-y(options) T = options, R = true. ?- T = options, nodebug(T), on_t(1,T), debug_topic(T,[debug(true)],R), on_t(2,T), debug_set(R,T), on_t(3,T). 1-n(options) 2-y(options) 3-n(options) T = options, R = false.
?- debug_topic( true, example ).
portray_clause(Term) if we are debugging Topic.
The main novelty is the introduction of abbreviated Goals, that print bespoke messages for often used debugging information. For example the following code ejects info on the legth of the list. Not only the code for calculating the length only happens if debugging for the topic ex, is on, but the message is also tailored to reporting lengths of lists.
?- debug(ex). ?- debug_call(ex, length, math_vars/[x,y,z]). % Length for list, math_vars: 3
With v1.3 the debuc/n shorthand was introduced. So debuc/1,2,3,4 are shorthands for debug_call/1,2,3,4.
?- Mtx = [h(a,b,c),r(1,2,3),r(4,5,6),r(7,8,9)], debuc(ex, dims, mtx/Mtx). Dimensions for matrix, mtx: nR: 4, nC: 3.
The predicate can work as a replacement to debug/3. That is, if Goal does not match any of the forms below, it will be interpreted as a message.
?- debuc(ex, 'A simple message in a ~a.', [bottle] ). A simple message in a bottle.
The predicate can be used to call arbitrary Goal and then print a message after it has successfull completed (see below).
When Goal is a known abbreviation from those shown below, the Arg usually qualifies the output generated.
As of v2 the last two arguments of the /4 version of the predicate were switched from Pfx and Arg
to Arg and Opts. Opts pass arbitary things to Goal, each abbreviation Goal can demand different options.
All debuc Goals can take prefix(Pfx) which corresponds to Pfx in the old /4 version, and pred(Fnc,Ar) or pred(Pid).
?- debuc(ex, enum, list_x/[x1,x1,x3], [pred(integral,2),prefix('At')] ).
% At predicate: integral/2 starting enumeration of list: list_x
% 1.x1
% 2.x1
% 3.x3
% At predicate: integral/2 ended enumeration of list: list_x
The predicate is relaxed about Opts. It can be a single term, which will be cast into a list.
?- debuc(ex, pwd, my_run, pred(bio_db,3) ). Predicate: bio_db/3 pwd at, my_run, is: '/home/nicos/pl/packs/private/debug_call/'
Goal in:
debug(Topic, Mess, MArgS). Goal is called in deterministic context.
Goal is called with extra arguments +Arg, -Mess and -MArgS.depth(Depth) (restricts items to print).call(Goal)
At 14:2:30 on 6th of Dec 2025 stop task: talking point
Reports reading from a file. Arg should be file specification suitable for locate/3.
Either loc(File,Exts) or simply File in which case Exts = ''.
As of v2.0 the default is to print the basename, use path(abs) in Opts.
depth(Depth) (restricts items to list).sel_name(Lnm) in Opts.pred(Fnc,Ar) or pred(Pid), the caller predicate, all(OrigOpts), shows all options,
internal(true), shows also '$' starting options.pred(Func,Ar), pred(Pid), the caller predicate, internal(true), shows also '$' starting options.farg() option.term_name(Tnm).arg(1)) and its current instantiation (arg(2))loc(File,Exts) or simply File in which case Exts = ''.
As of v2.0 the default is to print the basename, use path(abs) in Opts.
As of v2.1 all debuc Goals work with options prefix(Pfx) and pred(Ar,Fn) (also synonymed to pred(Pid)).
v2.2 introduced ability to pass formatting patterns and arguments via farg() option.
See file examples/exo.pl for a test suit including at least one example from each debuc Goal.
?- debug(ex).
?- debuc( ex, (length([a,b,c],L),write(len(L)),nl) ).
len(3)
L = 3.
?- debug_call(ex, length, list1/[x,y,z]).
% Length for list, list1: 3
?- debug_call(ex, length, [list1,list2]/[[x,y,z],[a,b,c]] prefix('some prefix')).
% some prefix lengths for lists, list1: 3, list2: 3
?- debuc(ex, wrote, loc(file,csv)).
% Could not locate wrote on file specified by: file, and extensions: csv
?- csv_write_file( 'file.csv', []).
?- debuc(ex, wrote, loc(file,csv)).
% Wrote on file: 'file.csv'
?- debuc(ex, wrote, loc(file,csv), path(abs)).
% Wrote on file: '/home/nicos/pl/lib/src/trace/file.csv'
?- debuc(ex, task(stop), 'write on file').
% At 15:44:1 on 2nd of Jul 2014 finished task: write on file.
?- debuc( ex, pwd, here ).
% Pwd at, here, is: '/home/nicos/.local/share/swi-prolog/pack/Downloads/bio_db_repo-publish/bio_db_repo-20.09.14/data/hs/maps/hgnc/'
true.
?- debuc( ex, pwd, false ).
% Pwd: '/home/nicos/.local/share/swi-prolog/pack/Downloads/bio_db_repo-publish/bio_db_repo-20.09.14/data/hs/maps/hgnc/'
true.
?- Etcs = [suv-17.09.26.txg,suv-17.09.21.txg], Etc = suv-17.09.26.txg,
debuc(suv, ns_sel, c(Etc,Etcs, sel_name('suv file') ).
Continuing with: suv-17.09.26.txg as the: suv file. From list: [suv-17.09.26.txg,suv-17.09.21.txg]
?- assert( (list_avg_mess(List,Mess,Args) :- length(List,Len), sum_list(List,Sum), Avg is Sum / Len, Mess = 'Avg: ~w', Args = Avg) ).
?- debuc( ex, call(list_avg_mess), [1,2,3] ).
Avg: 2
?- debuc( ex, call(list_avg_mess), [1,2,3], prefix('By call') ).
By call avg: 2
?- debuc( ex, call(list_avg_mess), [1,2,3], [pred(p1,2),prefix('By call')] ).
By call predicate: p1/2 avg: 2
At some point around SWI-Prolog 8, behaviour of debug/3 changed in being more strict about messages with no arguments. As of version 1.2 debug_call/3 can act as a replacement of debug/3 but with the old behaviour.
?- debug( ex, 'Messaging...', true ).
Messaging...
[[ EXCEPTION while printing message 'Messaging...'
with arguments user:true:
raised: format('too many arguments')
]]
true.
?- debuc( ex, 'Messaging...', true ).
% Messaging...
true.
?- debug( dbg ). ?- debug_consec( dbg, 'what:~w', when ). % what: when <- in blue ?- debug_consec( dbg, 'what:~w', when ). % what: when <- in magenta ?- debug_consec( dbg, [blue,green], 'what:~w', when ). % what: when <- in blue ?- debug_consec( dbg, [blue,green], 'what:~w', when ). % what: when <- in green
Version 0.2
?- debug_consec( dbg, magenta, 'what:~w', when ). % what: when <- in magenta