1:- module( debug_call, 2 [ 3 debug_call/2, 4 debug_call/3, 5 debug_call/4, 6 debuc/1, debuc/2, debuc/3, debuc/4, 7 debug_chain/2, debug_chain/3, 8 debug_consec/3, debug_consec/4, 9 debug_message/3, 10 debug_on/1, 11 debug_portray/2, 12 debug_set/2, 13 debugging_status/2, 14 debug_topic/2, 15 debug_topic/3, 16 debug_call_version/2, 17 debugging_topic/1 18 ] ). 19 20:- multifile(user:message_property/2). 21:- dynamic(debug_call_message_property/2). 22 23usermessage_property( Dbg, Property ) :- 24 debug_call_message_property( Dbg, Property ).
?- debug_call_version( -V, -D ). V = 2:3:0, D = date(2026,2,8).
*/
143debug_call_version(2:3:0, date(2026,2,8)). 144 145:- use_module(library(apply)). % maplist/4,... 146:- use_module(library(lists)). % member/4,... 147:- use_module(library(debug)). % debug/1,... 148:- use_module(library(filesex)). % directory_member/3. 149:- use_module(library(readutil)). % read_line_to_codes/2. 150:- use_module(library(process)). % process_create/3. 151:- use_module(library(readutil)). % read_line_to_codes/2. 152:- use_module(library(prolog_pack)). % pack_property/2. 153:- use_module(library(lib)). 154 155:- lib(source(debug_call), [homonyms(true),index(false)]). 156:- lib(stoics_lib:locate/3 ). 157:- lib(stoics_lib:en_list/2). 158:- lib(stoics_lib:message_report/3). 159:- lib(stoics_lib:datime_readable/1). 160:- lib(end(debug_call) ).
172debuc( Topic ) :- 173 debug( Topic ). 174debuc( Topic, Goal ) :- 175 debug_call( Topic, Goal ). 176debuc( Topic, Goal, Arg ) :- 177 debug_call( Topic, Goal, Arg ). 178debuc( Topic, Goal, Arg, Opts ) :- 179 debug_call( Topic, Goal, Arg, Opts ).
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
204debug_call( Topic, Goal ) :- 205 debugging_topic( Topic ), 206 !, 207 debug_call_goal( Topic, Goal ). 208debug_call( _Topic, _Goal ). 209 210debug_call_goal( Topic, Moal ) :- 211 ( Moal = Mod:Goal -> true; Goal = Moal, Mod=user ), 212 functor( Goal, Functor, Arity ), 213 Extra is Arity + 2, 214 current_predicate( Mod:Functor/Extra ), 215 !, 216 ( call(Mod:Goal,Mess,Args) -> 217 debug( Topic, Mess, Args ) 218 ; 219 true 220 ). 221debug_call_goal( _Topic, Goal ) :- 222 ( call(Goal) -> true; true ).
238debug_chain( Topic, Then ) :- 239 en_list( Then, Thens ), 240 maplist( debug_chain(Topic), Thens, _Priors ). 241 242debug_chain( Topic, Then, Prior ) :- 243 debugging_topic( Topic ), 244 !, 245 debugging_status( Then, Prior ), 246 debug( Then ). 247debug_chain( _Topic, _Then, true ). 248 % setting 3rd to true is a bit presumptious of its uses later on
lib(debug) does not create a record by inspecting the term (via expansion).
Particularly useful in sending uninstantiated Topics.
261debug_message( Topic, Mess, Args ) :-
262 call( debug, Topic, Mess, Args ).lib(debug) does not create a record by inspecting the term (via expansion).
Particularly useful in sending uninstantiated Topics.
274debugging_topic( Topic ) :-
275 Call =.. [debugging,Topic],
276 call( Call ).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.
293debugging_status( Topic, Status ) :- 294 debugging_topic( Topic ), 295 !, 296 Status = true. 297debugging_status( _Topic, 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
326debug_set( false, Topic ) :- 327 nodebug( Topic ). 328debug_set( true, Topic ) :- 329 debug( Topic ).
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.
360debug_topic( Topic, Opts, Restore ) :- 361 memberchk( debug(Dbg), Opts ), 362 Dbg == true, 363 !, 364 debug_topic_restore( Topic, Restore ), 365 debug( Topic ). 366debug_topic( Topic, _Opts, Restore ) :- % becomes default under this implementation 367 debug_topic_restore( Topic, Restore ), 368 nodebug( Topic ). 369 370debug_topic_restore( Topic, Restore ) :- 371 debugging_topic( Topic ), 372 !, 373 Restore = true. 374debug_topic_restore( _Topic, false ).
?- debug_topic( true, example ).
388debug_topic( true, Topic ) :- 389 debug( Topic ). 390debug_topic( false, Topic ) :- 391 nodebug(Topic).
397debug_on( Topic ) :-
398 asserta( prolog_debug:debugging(Topic,true,[user_error])).portray_clause(Term) if we are debugging Topic.
407debug_portray( Topic, Term ) :- 408 debugging_topic( Topic ), 409 !, 410 portray_clause( Term ). 411debug_portray( _Topic, _Term ).
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.check_point() and comment()- as does stat.
The latter allows for reporting without '%' so terms can be read in by read/1 or consulted.
In addition, option sub() can be used the subdirectories ofArg==true.depth(Depth) (restricts items to print).call(Goal)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 if the full path to the file is needed.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.Arg==false, location is not shown)- see examples.Arg==true.check_point() and comment().
The latter allows for reporting without '%' so terms can be read in by read/1 or consulted.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 if the full path to the file is needed.
As of v2.1 almosst 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.
Opts supported by all debugoals
pred(F/A)) adds predicate caller identfication to messagetask(start),task(stop)]Opts for specific debugoals
Comm==false print message through format without '%' (portray_message) machineary [stat- print readable terms]
?- 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
?- debuc(ex, stat, runtime, true).
stat(runtime,[182,4]).
true.
?- debuc(ex, stat, runtime, [check_point(here),comment(false)]). % note this does not have a precedding percentage char
stat(here,runtime,[193,11]).
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.
650debug_call( Topic, Goal, Arg ) :- 651 debug_call( Topic, Goal, Arg, [] ). 652 653debug_call( Topic, Goal, Arg, OptsPrv ) :- 654 debugging_topic( Topic ), 655 !, 656 en_list( OptsPrv, Opts ), 657 debugging_call( Topic, Goal, Arg, Opts ). 658debug_call( _Topic, _Goal, _Arg, _Opts ). 659 660debugging_call( Topic, call(Goal), Arg, Opts) :- 661 !, 662 call( Goal, Arg, Gess, Grgs ), 663 !, 664 debug_call_message_opts( Gess, Grgs, Mess, Args, Opts ), 665 debug_message( Topic, Mess, Args ). 666debugging_call( Topic, call_opts(Goal), Arg, Opts ) :- 667 !, 668 call( Goal, Arg, Gess, Grgs, Opts ), 669 debug_call_message_opts( Gess, Grgs, Mess, Args, Opts ), 670 debug_message( Topic, Mess, Args ). 671debugging_call( Topic, Goal, Arg, Opts ) :- 672 debug_call_topic( Goal, Arg, Opts, Topic ), 673 !. 674debugging_call( Topic, Goal, Mess, Args ) :- 675 compound( Goal ), 676 call( Goal ), 677 !, 678 debug_message( Topic, Mess, Args ). 679% 20.03.07: this makes debug_call/3 a replacement for debug/3... 680debugging_call( Topic, Mess, ArgsPrv, _DbgCallArgs ) :- 681 % as of SWI-Prolog 8.?.? there is an error thrown when true is used instead of [] as 3rd arg of debug/3 682 atomic( Mess ), 683 !, 684 ( ArgsPrv == true -> Args = []; en_list(ArgsPrv,Args) ), 685 debug( Topic, Mess, Args ). 686debugging_call( Topic, Goal, Mess, Args ) :- 687 Called = debug_call(Topic,Goal,Mess,Args), 688 message_report( 'failure ignored on: ~w', Called, warning ).
?- 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
722debug_consec( Topic, Mess, Args ) :- 723 Clrs = [blue,magenta], 724 debug_consec( Topic, Clrs, Mess, Args ). 725 726debug_consec( Topic, ClrS, Mess, Args ) :- 727 debugging_topic( Topic ), 728 !, 729 ( is_list(ClrS) -> Clrs = ClrS; Clrs = [ClrS] ), 730 debug_consec_topic( Topic, Clrs, Mess, Args ). 731debug_consec( _Topic, _Clrs, _Mess, _Args ). 732 733debug_consec_topic( Topic, Clrs, Mess, Args ) :- 734 with_output_to( atom(Topicat), write_term(Topic,[]) ), 735 ( nb_current(Topicat,Value) -> true; Value = 1 ), 736 ( nth1(Value, Clrs, Clr) -> true; Clrs = [Clr|_] ), 737 debug_consec_color( Topic, Clr, Mess, Args ), 738 length( Clrs, Len ), 739 ( Value < Len -> Next is Value + 1; Next is 1 ), 740 nb_setval( Topicat, Next ). 741 742debug_consec_color( Topic, Clr, Mess, Args ) :- 743 user:message_property( debug(_), color(Attrs) ), 744 !, 745 retractall( debug_call_message_property(debug(_),color(_)) ), 746 assert( debug_call_message_property(debug(_),color(fg(Clr))) ), 747 debug_message( Topic, Mess, Args ), 748 retractall( debug_call_message_property(debug(_),color(_)) ), 749 assert( debug_call_message_property(debug(_),color(Attrs)) ). 750debug_consec_color( Topic, Clr, Mess, Args ) :- 751 assert( debug_call_message_property(debug(_),color(fg(Clr))) ), 752 debug_message( Topic, Mess, Args ), 753 retractall( debug_call_message_property(debug(_),color(_)) ). 754 755debug_call_topic( info, Arg, Bogs, _Topic ) :- 756 ( (\+ var(Arg),Arg = Mess/Args) -> 757 true 758 ; 759 % fixme: not sure what to do here ? 760 Mess = Arg, 761 Args = [] 762 ), 763 debug_call_message_opts( Mess, Args, Prefixed, Prgs, Bogs ), 764 phrase('$messages':translate_message(debug(Prefixed,Prgs)), Lines), 765 print_message_lines(current_output, kind(informational), Lines). 766debug_call_topic( dims, NamesPrv/MtxsPrv, Bogs, Topic ) :- 767 ( is_list(NamesPrv) -> Names=NamesPrv, MtxsPrv=Mtxs, With = 'Dimensions for matrices, ' 768 ; [NamesPrv] = Names, [MtxsPrv]=Mtxs, With = 'Dimensions for matrix, ' 769 ), 770 maplist( debug_mtx_dims, Mtxs, NRows, NCols ), 771 findall( PartM, (member(_,Names),PartM='~w: nR: ~d, nC: ~d.'), MParts ), 772 atomic_list_concat( MParts, '', Right ), 773 findall( [Name,NRow,NCol], (nth1(N,Names,Name),nth1(N,NRows,NRow),nth1(N,NCols,NCol)), NNest ), 774 flatten( NNest, Vargs ), 775 atom_concat( With, Right, Vess ), 776 debug_call_message_opts( Vess, Vargs, Message, Args, Bogs ), 777 debug_message( Topic, Message, Args ). 778debug_call_topic( enum, InArg, Bogs, Topic ) :- 779 ground( InArg ), 780 ( InArg = Left/Term -> true; Left = unnamed, Term = InArg ), 781 ( is_list(Term) -> 782 length( Term, Len ), 783 number_codes( Len, LenCs ), 784 length( LenCs, SpcLen ), 785 debug_call_topic_list_delim( Left, Topic, 'Starting enumeration of list: ~w', Bogs ), 786 ( memberchk(depth(Depth), Bogs) -> true; Depth = inf ), 787 debug_call_topic_enum( Term, 1, Depth, SpcLen, Topic ), 788 debug_call_topic_list_delim( Left, Topic, 'Ended enumeration of list: ~w', Bogs ) 789 ; 790 Term =.. [Func|Args], 791 length( Args, Len ), 792 number_codes( Len, LenCs ), 793 length( LenCs, SpcLen ), 794 atomic_list_concat( ['Starting enumeration of term: ~w (func: ',Func,')'], StrMess ), 795 debug_call_topic_list_delim( Left, Topic, StrMess, Bogs ), 796 ( memberchk(depth(Depth), Bogs) -> true; Depth = inf ), 797 debug_call_topic_enum( Args, 1, Depth, SpcLen, Topic ), 798 atomic_list_concat( ['Ended enumeration of term: ~w (func: ',Func,')'], EndMess ), 799 debug_call_topic_list_delim( Left, Topic, EndMess, Bogs ) 800 ). 801debug_call_topic( length, NamesPrv/ListsPrv, Bogs, Topic ) :- 802 ( is_list(NamesPrv) -> Names=NamesPrv, ListsPrv=Lists, With = 'Lengths for lists, ' 803 ; [NamesPrv] = Names, [ListsPrv]=Lists, With = 'Length for list, ' 804 ), 805 maplist( length, Lists, Lengths ), 806 findall( ['~w: ~w',', '], member(_,Lengths), WsNest ), 807 flatten( WsNest, WsL ), 808 once( append(WsLComma,[_],WsL) ), 809 append( WsLComma, ['.'], WsLDot ), 810 atomic_list_concat( WsLDot, '', Right ), 811 findall( [Name,Length], (nth1(N,Names,Name),nth1(N,Lengths,Length)), NLNest ), 812 flatten( NLNest, NLs ), 813 atom_concat( With, Right, Vess ), 814 debug_call_message_opts( Vess, NLs, Message, Args, Bogs ), 815 debug_message( Topic, Message, Args ). % do the messaging 816debug_call_topic( list, InArg, Bogs, Topic ) :- 817 ground( InArg ), 818 ( InArg = Left/List -> 819 ( Left = Hdr/Ftr -> true ; Hdr = Left, Ftr = Left ) 820 ; 821 List = InArg, Hdr = unamed, Ftr = unamed 822 ), 823 debug_call_topic_list_delim( Hdr, Topic, 'Starting listing of list: ~w', Bogs), 824 ( memberchk(depth(Depth),Bogs) -> 825 length( Clean, Depth ), 826 ( append(Clean,[H|T],List) -> 827 maplist( debug_message(Topic,'~w'), Clean ), 828 length( [H|T], Xen ), 829 ( Xen =:= 1 -> 830 Mess = '... + ~d other element' 831 ; 832 Mess = '... + ~d other elements' 833 ), 834 debug_message( Topic, Mess, Xen ) 835 ; 836 maplist( debug_message(Topic,'~w'), List ) 837 ) 838 ; 839 maplist( debug_message(Topic,'~w'), List ) 840 ), 841 debug_call_topic_list_delim( Ftr, Topic, 'Ended listing of list: ~w', Bogs ). 842debug_call_topic( odir, Odir, Bogs, Topic ) :- 843 ( exists_directory(Odir) -> 844 Mess = 'Output in directory: ~w' 845 ; 846 Mess = 'Output (claimed) in (non-existing) directory: ~w' 847 ), 848 debug_call_message_opts( Mess, [Odir], Message, Args, Bogs ), 849 debug_message( Topic, Message, Args ). 850debug_call_topic( option, Opt, Bogs, Topic ) :- 851 Ness = 'Option selected: ~w', 852 ( (memberchk(all(OrgOpts),Bogs),is_list(OrgOpts)) -> 853 ( memberchk(internal(true),Bogs) -> 854 RdcOpts = OrgOpts 855 ; 856 findall( R, (member(R,OrgOpts),functor(R,F,_),\+(atom_concat('$',_,F))), RdcOpts ) 857 ), 858 atom_concat( Ness, ' from options: ~w', Mess ), 859 Mrgs = [Opt,RdcOpts] 860 ; 861 atom_concat( Ness, '.', Mess ), 862 [Opt] = Mrgs 863 ), 864 debug_call_message_opts( Mess, Mrgs, Message, Args, Bogs ), 865 debug_message( Topic, Message, Args ). 866debug_call_topic( options, RepOpts, Bogs, Topic ) :- 867 Ness = 'Options: ~w', 868 ( memberchk(internal(true),Bogs) -> 869 RepOpts = RdcOpts 870 ; 871 findall( R, (member(R,RepOpts),functor(R,F,_),\+(atom_concat('$',_,F))), RdcOpts ) 872 ), 873 debug_call_message_opts( Ness, [RdcOpts], Message, Args, Bogs ), 874 debug( Topic, Message, Args ). 875debug_call_topic( duh, Dir, Bogs, Topic ) :- 876 debug_call_duh_dir( Dir, PaPair ), 877 ( memberchk(sub(true), Bogs ) -> 878 findall( Os, directory_member(Dir, Os, []), Oses ), 879 maplist( debug_call_duh_dir, Oses, SubPairs ), 880 Pairs = [PaPair|SubPairs] 881 ; 882 Pairs = [PaPair] 883 ), 884 ( memberchk(check_point(Point),Bogs) -> 885 Rec = duh(Point,Pairs) 886 ; 887 Rec = duh(Pairs) 888 ), 889 debuc_call_topic_term( Rec, Topic, Bogs ). 890debug_call_topic( stat, Key, Bogs, Topic ) :- 891 statistics( Key, Stat ), 892 ( memberchk(check_point(Point),Bogs) -> 893 Rec = stat(Point,Key,Stat) 894 ; 895 Rec = stat(Key,Stat) 896 ), 897 debuc_call_topic_term( Rec, Topic, Bogs ). 898debug_call_topic( term, Derm, Bogs, Topic ) :- 899 ( memberchk(term_name(Tnm),Bogs) -> 900 Mess = 'Reporting term (~w): ~w', 901 Mrgs = [Tnm,Derm] 902 ; 903 Mess = 'Reporting term: ~w', 904 Mrgs = [Derm] 905 ), 906 debug_call_message_opts( Mess, Mrgs, Message, Args, Bogs ), 907 debug_message( Topic, Message, Args ). 908debug_call_topic( var, DbgTerm, Bogs, Topic ) :- 909 arg( 1, DbgTerm, Var ), 910 arg( 2, DbgTerm, Val ), 911 Mess = 'Variable: ~a, value: ~w', 912 debug_call_message_opts( Mess, [Var,Val], Message, Args, Bogs ), 913 debug_message( Topic, Message, Args ). 914debug_call_topic( session, _Derm, Bogs, Topic ) :- 915 ( memberchk(in_module(Mod), Bogs) -> true; Mod = user), 916 current_prolog_flag( version_data, Swi ), % Swi = swi(9, 3, 34, []). 917 Swi = swi(Mj,Mn,Fx,Inc), 918 ( Inc == [] -> 919 atomic_list_concat( [Mj,Mn,Fx], ':', Vers ) 920 ; 921 atomic_list_concat( [Mj,Mn,Fx,Inc], ':',Vers ) 922 ), 923 debug_message( Topic, 'Session Info', [] ), 924 ( current_prolog_flag(version_git, Git) -> % Git = '9.3.34-41-g8cf975236'. 925 atomic_list_concat( ['Interpreter is SWI-Prolog ',Vers,', [Git: ',Git,'].'], Mess ) 926 ; 927 atomic_list_concat( ['Interpreter is SWI-Prolog ',Vers,'.'], Mess ) 928 ), 929 debug_call_message_opts( Mess, [], Message, Args, Bogs ), 930 debug_message( Topic, Message, Args ), 931 % find where alias pack points to 932 once( (file_search_path(pack,PackPath),atomic(PackPath)) ), 933 debug_call_topic_session_predicate_file_prefixed( PackPath, Mod, pack, Lacks ), 934 findall( APack-ItsVers, (member(APack,Lacks),pack_property(APack,version(ItsVers))), PVs ), 935 findall( Stoic-VersInfo, ( Mod:predicate_property(P,file(_)), 936 functor(P,Fun,Ari), 937 atom_concat(Stoic,'_version',Fun), 938 ( Mod:predicate_property(P,imported_from(Stoic)) -> 939 true 940 ; 941 Mod:predicate_property(P,exported) 942 ), 943 ( Ari =:= 3 -> 944 G =.. [Fun,Ser,Sdt,_], 945 call(Mod:G) 946 ; % defaulty 2 947 Ari =:= 2, 948 G =.. [Fun,Ser,Sdt], 949 call(Mod:G) 950 ), 951 VersInfo = (Ser @< Sdt) 952 ), 953 SVs ), 954 ( SVs == [] -> 955 true 956 ; 957 ( SVs == [_] -> 958 debug_message( Topic, 'Pack with predicated version info.', [] ) 959 ; 960 debug_message( Topic, 'Packs with predicated version info.', [] ) 961 ), 962 debug_call_topic_versions_predicated( SVs, PVs, Topic, RemPVs ) 963 ), 964 ( RemPVs = [] -> 965 true 966 ; 967 ( RemPVs = [_] -> 968 debug_message( Topic, 'Pack with version from pack file only.', [] ) 969 ; 970 debug_message( Topic, 'Packs with version from pack file only.', [] ) 971 ), 972 findall( _, (member(P-V,RemPVs),debug_message(Topic,'~w-~w',[P,V])), _ ) 973 ), 974 once( (file_search_path(swi,SwiPath),atomic(SwiPath)) ), 975 debug_call_topic_session_predicate_file_prefixed( SwiPath, Mod, boot, Boots ), 976 debug_message( Topic, 'System boot files loaded.', [] ), 977 findall( _, (member(Boot,Boots),debug_message(Topic,'~w',[Boot])), _ ), 978 directory_file_path( SwiPath, library, LibPath ), 979 debug_call_topic_session_predicate_file_prefixed( LibPath, Mod, rel, Libs ), 980 ( Libs = [] -> 981 debug_message( Topic, 'No system libraries found loaded.', [] ) 982 ; 983 ( Libs =[_] -> 984 debug_message( Topic, 'System library loaded.', [] ) 985 ; 986 debug_message( Topic, 'System libraries loaded.', [] ) 987 ), 988 findall( _, (member(Lib,Libs),debug_message(Topic,'~w',[Lib])), _ ) 989 ), 990 findall( AppF, ( Mod:predicate_property(_,file(AppF)), 991 ( atom_concat(PackPath,PackPsfx,AppF) -> 992 % fixme: check PackTop below, against loaded ? 993 catch( atomic_list_concat([_Empty,_PackTop,TopSub|_],'/',PackPsfx),_,fail), 994 \+ memberchk(TopSub,[prolog,src]) 995 ; 996 true 997 ), 998 \+atom_concat(SwiPath,_,AppF) 999 ), 1000 AppFsL ), 1001 sort( AppFsL, AppFs ), 1002 ( AppFs = [] -> 1003 debug_message( Topic, 'There where no application files loaded.', [] ) 1004 ; 1005 ( AppFs = [_] -> 1006 debug_message( Topic, 'There is one application file loaded.', [] ) 1007 ; 1008 debug_message( Topic, 'Application files loaded.', [] ) 1009 ), 1010 findall( AnAF, (member(AnAF,AppFs),debug_message(Topic,'~w',[AnAF])), _ ) 1011 ), 1012 debug_message( Topic, 'Session Info End', [] ). 1013debug_call_topic( version, Derm, Bogs, Topic ) :- 1014 ( atomic(Derm) -> 1015 atom_concat( Derm, '_version', Verm ), 1016 ( current_predicate(Verm/2) -> 1017 Goal =.. [Verm,V,D], 1018 once(Goal) 1019 ; 1020 ( current_predicate(Verm/3) -> 1021 Goal =.. [Verm,V,D,_], 1022 once(Goal) 1023 ; 1024 ( pack_property(Derm,version(V)) -> 1025 D = no_date 1026 ; 1027 ( current_predicate(Derm/2) -> 1028 Goal =.. [Derm,V,D], 1029 once(Goal) 1030 ; 1031 V = no_vers, D = no_date 1032 ) 1033 ) 1034 ) 1035 ), 1036 Mrgs = [Derm,V,D] 1037 ; 1038 ( functor(Derm,_,2) -> 1039 arg( 1, Derm, Sw ), 1040 arg( 2, Derm, V ), 1041 Mrgs = [Sw,V,no_date] 1042 ; 1043 ( functor(Derm,_,3) -> 1044 arg( 1, Derm, Sw ), 1045 arg( 2, Derm, V ), 1046 arg( 3, Derm, D ), 1047 Mrgs = [Sw,V,D] 1048 ; 1049 Mrgs = [Derm,no_vers,no_date] 1050 ) 1051 ) 1052 ), 1053 ( D == no_date -> 1054 ( V == no_vers -> 1055 Mess = 'Using ~w (no version or publication date available).', 1056 Mrgs = [A|_], 1057 Crgs = [A] 1058 ; 1059 Mess = 'Using ~w, at version: ~w.', 1060 Mrgs = [A,B|_], 1061 Crgs = [A,B] 1062 ) 1063 ; 1064 Mess = 'Using ~w, at version: ~w (published on: ~w).', 1065 Mrgs = Crgs 1066 ), 1067 debug_call_message_opts( Mess, Crgs, Message, Args, Bogs ), 1068 debug_message( Topic, Message, Args ). 1069debug_call_topic( wrote, ForLoc, Bogs, Topic ) :- 1070 ( ForLoc = loc(Spec,Ext) -> true; Spec=ForLoc, Ext = '' ), 1071 catch( locate(Spec,Ext,Loc), Excp, true ), 1072 MessW = 'Wrote on file: ~p', 1073 debug_call_location_exception_message( Excp, write, Loc, MessW, Mess, Bogs, Mrgs ), 1074 debug_call_message_opts( Mess, Mrgs, Message, Args, Bogs ), 1075 debug_message( Topic, Message, Args ). 1076debug_call_topic( read, ForLoc, Bogs, Topic ) :- 1077 debug_call_topic( input, ForLoc, Bogs, Topic ). 1078debug_call_topic( input, ForLoc, Bogs, Topic ) :- 1079 ( ForLoc = loc(Spec,Ext) -> true; Spec=ForLoc, Ext = '' ), 1080 catch( locate(Spec,Ext,Loc), Excp, true ), 1081 MessW = 'Input from file: ~p', 1082 debug_call_location_exception_message( Excp, input, Loc, MessW, Mess, Bogs, Mrgs ), 1083 debug_call_message_opts( Mess, Mrgs, Message, Args, Bogs ), 1084 debug_message( Topic, Message, Args ). 1085debug_call_topic( task(Whc), TaskPrv, Bogs, Topic ) :- 1086 datime_readable( Readable ), 1087 debug_call_topic_time_which_readable( Whc, Whcable ), 1088 ( compound(TaskPrv) -> term_to_atom( TaskPrv, Task ); TaskPrv = Task ), 1089 atomic_list_concat( [Readable,' ',Whcable,' task: ',Task,'.'], '', Mess ), 1090 debug_call_message_opts( Mess, [], Message, Args, Bogs ), 1091 debug_message( Topic, Message, Args ). 1092debug_call_topic( start, Arg, Bogs, Topic ) :- 1093 Mess = 'Starting: ~w', 1094 ( Arg == true -> Rep = Topic; Rep = Arg ), 1095 debug_call_message_opts( Mess, [Rep], Message, Args, Bogs ), 1096 debug_message( Topic, Message, Args ). 1097debug_call_topic( end, Arg, Bogs, Topic ) :- 1098 Mess = 'Finished: ~w', 1099 ( Arg == true -> Rep = Topic; Rep = Arg ), 1100 debug_call_message_opts( Mess, [Rep], Message, Args, Bogs ), 1101 debug_message( Topic, Message, Args ). 1102debug_call_topic( pwd, Stage, Bogs, Topic ) :- 1103 working_directory( Pwd, Pwd ), 1104 ( Stage == false -> 1105 Mess = 'Pwd: ~p', Mrgs = [Pwd] 1106 ; 1107 Mess = 'Pwd at, ~w, is: ~p', Mrgs = [Stage,Pwd] 1108 ), 1109 debug_call_message_opts( Mess, Mrgs, Message, Args, Bogs ), 1110 debug_message( Topic, Message, Args ). 1111debug_call_topic( ns_sel, Term, Bogs, Topic ) :- 1112 arg( 1, Term, Fst ), 1113 arg( 2, Term, Sec ), 1114 ( memberchk(sel_name(Trd),Bogs) -> 1115 Mess = 'Continuing with: ~w as the: ~w. From list: ~w', 1116 MArgs= [Fst,Trd,Sec] 1117 ; 1118 Mess = 'Continuing with: ~w from list: ~w', 1119 MArgs= [Fst,Sec] 1120 ), 1121 debug_call_message_opts( Mess, MArgs, Message, Args, Bogs ), 1122 debug_message( Topic, Message, Args ). 1123 1124debug_call_topic_session_predicate_file_prefixed( Path, Mod, Iface, Lacks ) :- 1125 findall( APack, ( Mod:predicate_property(_Pead, file(File)), 1126 atom_concat(Path, Psfx, File), 1127 ( Iface == pack -> 1128 atomic_list_concat(['',APack|_], '/', Psfx) 1129 ; 1130 ( atom_concat('/',APack,Psfx) -> 1131 ( Iface == boot -> 1132 \+ atom_concat( library, _, APack ) 1133 ; 1134 true 1135 ) 1136 ; 1137 Psfx = APack 1138 ) 1139 ) 1140 ), 1141 AllPacks ), 1142 sort( AllPacks, Lacks ). 1143 1144debug_call_topic_versions_predicated( [], PVs, _Topic, RemPVs ) :- 1145 PVs = RemPVs. 1146debug_call_topic_versions_predicated( [Pack-SVers|T], PVs, Topic, RemPVs ) :- 1147 ( select(Pack-InfoVer,PVs,NxtPVs) -> 1148 debug_message( Topic, '~w-~w (Pack file version: ~w)', [Pack,SVers,InfoVer] ) 1149 ; 1150 debug_message( Topic, '~w-~w', [Pack,SVers] ), 1151 PVs = NxtPVs 1152 ), 1153 debug_call_topic_versions_predicated( T, NxtPVs, Topic, RemPVs ). 1154 1155debuc_call_topic_term( Rec, Topic, Bogs ) :- 1156 ( memberchk(comment(false),Bogs) -> 1157 format( '~q.\n', [Rec] ) 1158 ; 1159 debug_call_message_opts( '~w.', [Rec], Message, Args, Bogs ), 1160 debug_message( Topic, Message, Args ) 1161 ). 1162 1163debug_call_topic_enum( [], _I, _Depth, _Len, _Topic ). 1164debug_call_topic_enum( [H|T], I, Depth, Len, Topic ) :- 1165 ( I > Depth -> 1166 Rem = [], 1167 length( [H|T], HTen ), 1168 ( HTen =:= 1 -> 1169 Mess = '... + ~d other element' 1170 ; 1171 Mess = '... + ~d other elements' 1172 ), 1173 debug_message( Topic, Mess, HTen ) 1174 ; 1175 T = Rem, 1176 number_codes( I, ICs ), 1177 length( ICs, ICsLen ), 1178 PadLen is Len - ICsLen, 1179 findall( ' ', between(1,PadLen,_), Spcs ), 1180 atomic_list_concat( Spcs, '', Pad ), 1181 atomic_list_concat( [Pad,'~d.~w'], '', Mess ), 1182 debug_message( Topic, Mess, [I,H] ) 1183 ), 1184 J is I + 1, 1185 debug_call_topic_enum( Rem, J, Depth, Len, Topic ). 1186 1187debug_call_topic_list_delim( ListName, Topic, Std, Bogs ) :- 1188 debug_call_message_opts( Std, [ListName], Mess, Args, Bogs ), 1189 debug_message( Topic, Mess, Args ). 1190 1191debug_call_topic_time_which_readable( Wch, Wchable ) :- 1192 debug_call_topic_time_which_readable_known( Wch, Wchable ), 1193 !. 1194debug_call_topic_time_which_readable( Wch, Wch ). 1195 1196debug_call_topic_time_which_readable_known( start, starting ). 1197debug_call_topic_time_which_readable_known( finish, finished ). 1198 1199debug_call_location_exception_message( Var, _Dir, Loc, MessI, MessO, Opts, Args ) :- 1200 var(Var), 1201 !, 1202 MessI = MessO, 1203 ( memberchk(path(abs),Opts) -> 1204 Args = [Loc] 1205 ; 1206 file_base_name( Loc, Arg ), 1207 Args = [Arg] 1208 ). 1209debug_call_location_exception_message( locate(cannot_locate(Spec,Ext)), Dir, _Loc, _MessI, Mess, _Opts, Args ) :- 1210 atomic_list_concat( ['Could not locate',Dir,'file specified by: ~w, and extensions: ~w'], ' ', Mess ), 1211 Args = [Spec,Ext]. 1212debug_call_location_exception_message( Error, _Dir, _Loc, _MessI, _Mess, _Opts, _Args ) :- 1213 % fixme: 1214 throw( debug_call_caught(Error) ). 1215 1216debug_mtx_dims( [], 0, 0 ) :- 1217 !. 1218debug_mtx_dims( Rows, NRows, NCols ) :- 1219 length( Rows, NRows ), 1220 Rows = [Hdr|_], 1221 ( is_list(Hdr) -> length(Hdr,NCols); functor(Hdr,_,NCols) ). 1222 1223debug_message_prefixed( [], Standard, Standard ) :- !. 1224debug_message_prefixed( '', Standard, Standard ) :- !. 1225debug_message_prefixed( prefix(Pfx), Standard, Prefixed ) :- 1226 !, 1227 debug_message_prefixed( [prefix(Pfx)], Standard, Prefixed ). 1228debug_message_prefixed( [H|T], Standard, Prefixed ) :- 1229 memberchk( prefix(Pfx), [H|T] ), 1230 !, 1231 debug_message_prefixed_atom( Pfx, Standard, Prefixed ). 1232debug_message_prefixed( _, Standard, Standard ). 1233 1234debug_call_message_opts( Std, Srgs, Mess, Args, Opts ) :- 1235 debug_call_pred_in_opts_mess( Std, Srgs, Pess, Args, Opts ), 1236 debug_message_prefixed( Opts, Pess, Mess ). 1237 1238debug_call_pred_in_opts_mess( Std, Opt, Prefixed, Prgs, Bogs ) :- 1239 en_list( Opt, Opts ), 1240 ( debug_call_pred_in_opts(Pid, Bogs) -> 1241 Pfx = 'Predicate: ~w', 1242 debug_message_prefixed_atom( Pfx, Std, Prefixed ), 1243 PrgsPrv = [Pid|Opts] 1244 ; 1245 Prefixed = Std, 1246 PrgsPrv = Opts 1247 ), 1248 debug_call_pred_in_opts_mess_format_args( PrgsPrv, Prgs, Bogs ). 1249 1250debug_call_pred_in_opts( Pid, Opts ) :- 1251 memberchk( pred(Fun,Ar), Opts ), 1252 !, 1253 Fun/Ar = Pid. 1254debug_call_pred_in_opts( Pid, Opts ) :- 1255 memberchk( pred(Pid), Opts ). 1256 1257debug_call_pred_in_opts_mess_format_args( PrgsPrv, Prgs, Bogs ) :- 1258 findall( Farg, member(farg(Farg),Bogs), Fargs ), 1259 append( PrgsPrv, Fargs, Prgs ). 1260 1261debug_message_prefixed_atom( Pfx, Standard, Prefixed ) :- 1262 sub_atom( Standard, 0, 1, Aft, Fst ), 1263 downcase_atom( Fst, Low ), 1264 sub_atom( Standard, 1, Aft, 0, Right ), 1265 atomic_list_concat( [Pfx,' ',Low,Right], Prefixed ). 1266 1267debug_call_duh_dir( Dir, Pair ) :- 1268 setup_call_cleanup( 1269 process_create(path(du), ['-h','-s',Dir], 1270 [ stdout(pipe(Out)) 1271 ]), 1272 read_line_to_codes( Out, LineCs ), 1273 close(Out)), 1274 atom_codes( Line, LineCs ), 1275 atomic_list_concat( [Size,Item], '\t', Line ), 1276 Pair = Item-Size
Debugging with calls.
Debugging information focusing on avoiding 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.plfor a full pallette of examples.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. ?- debuc(ex, stat, runtime, true). % stat(runtime,[182,4]). true. ?- debuc(ex, stat, runtime, [check_point(here),comment(false)]). stat(here,runtime,[193,11]). true. ?- debuc(ex, stat, testo, [sub(true),comment(false)]). duh([testo-8.0K,testo/file_a-0,testo/sub_1-4.0K]).Variable topics
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 =.. .Pack info
*/
options_debug( Opts, Mess, Args )only writes if Opts containsdebug(true). maybe this should be part ofpack(options)lib(debug)'s expansions