The number of questions asked by the declarative debugger before it pinpoints the location of a bug can be reduced by giving it extra information. The kind of extra information that can be given and how to convey this information are explained in this section.
An incorrect subterm can be tracked to the call that bound the subterm from within the interactive term browser (see Declarative debugging commands).
After issuing a ‘track’ command, the next question asked by the declarative debugger will be about the call that bound the incorrect subterm, unless that call was eliminated as a possible bug because of an answer to a previous question or the call that bound the subterm was not traced.
For example consider the following fragment of a program that calculates payments for a loan:
:- type payment ---> payment( date :: date, amount :: float ). :- type date ---> date(int, int, int). % date(day, month, year). :- pred get_payment(loan::in, int::in, payment::out) is det. get_payment(Loan, PaymentNo, Payment) :- get_payment_amount(Loan, PaymentNo, Amount), get_payment_date(Loan, PaymentNo, Date), Payment = payment(Date, Amount).
get_payment produces an incorrect result and the
declarative debugger asks:
get_payment(loan(...), 10, payment(date(9, 10, 1977), 10.000000000000)). Valid?
Then if we know that this is the right payment amount for the given loan,
but the date is incorrect, we can track the date(...) subterm and the
debugger will then ask us about
get_payment(loan(...), 10, payment(date(9, 10, 1977), 10.000000000000)). Valid? browse browser> cd 3/1 browser> ls date(9, 10, 1977) browser> track get_payment_date(loan(...), 10, date(9, 10, 1977)). Valid?
Thus irrelevant questions about
get_payment_amount are avoided.
If, say, the date was only wrong in the year part, then we could also have tracked the year subterm in which case the next question would have been about the call that constructed the year part of the date.
This feature is also useful when using the procedural debugger. For example, suppose that you come across a ‘CALL’ event and you would like to know the source of a particular input to the call. To find out you could first go to the final event by issuing a ‘finish’ command. Invoke the declarative debugger with a ‘dd’ command and then track the input term you are interested in. The next question will be about the call that bound the term. Issue a ‘pd’ command at this point to return to the procedural debugger. It will now show the final event of the call that bound the term.
Note that this feature is only available if the executable is compiled in a .decldebug grade or with the ‘--trace rep’ option. If a module is compiled with the ‘--trace rep’ option but other modules in the program are not then you will not be able to track subterms through those other modules.
The declarative debugger can also be told to assume that certain predicates, functions or entire modules do not contain any bugs. The declarative debugger will never ask questions about trusted predicates or functions. It is a good idea to trust standard library modules imported by a program being debugged.
The declarative debugger can be told which predicates/functions it can trust before the ‘dd’ command is given. This is done using the ‘trust’, ‘trusted’ and ‘untrust’ commands at the mdb prompt (see Declarative debugging mdb commands for details on how to use these commands).
Trust commands may be placed in the ‘.mdbrc’ file which contains default settings for mdb (see Mercury debugger invocation). Trusted predicates will also be exported with a ‘save’ command (see Miscellaneous commands).
During the declarative debugging session the user may tell the declarative debugger to trust the predicate or function in the current question. Alternatively the user may tell the declarative debugger to trust all the predicates and functions in the same module as the predicate or function in the current question. See the ‘trust’ command in Declarative debugging commands.
If a search mode is given when invoking the declarative debugger then that search mode will be used, unless (a) a subterm is tracked during the session, or (b) the user has not answered ‘no’ to any questions yet, in which case top-down search is used until ‘no’ is answered to at least one question.
If no search mode is specified with the ‘dd’ command then the search mode depends on if the ‘--resume’ option is given. If it is then the previous search mode will be used, otherwise top-down search will be used.
You can check the search mode used to find a particular question by issuing an ‘info’ command at the question prompt in the declarative debugger. You can also change the search mode from within the declarative debugger with the ‘mode’ command.