home *** CD-ROM | disk | FTP | other *** search
- LISTING 1.
- Bug finding strategy in PROLOG.
- find_failing_subgoal( Given_goal, Subgoal_which_is_bug) :-
- this_is_the_problem( Subgoal_which_is_bug), !.
- find_failing_subgoal( Given_goal, Subgoal_which_is_bug) :-
- find_failing_subgoal_of_my_clauses( Given_goal,
- Intermediate_problem_goal),
- find_failing_subgoal( Intermediate_problem_goalGiven_goal,
- Subgoal_which_is_bug).
-
- LISTING 2.
- Testing for a list of integers
- with bug.
- integers( []) :-
- !,
- fail.
- integers( [H|T]) :-
- integer(H),
- integers(T).
-
- LISTING 3.
- Report on bug in Listing 2.
- HERE IS THE BUG ANALYSIS :
- THE TOP LEVEL BUG...
- The user-supplied goal integers([1]) failed.
-
- GOING DOWN A LEVEL,
- The goal at this level is integers([1]) which failed.
- Clause 2 of integers / 1 failed.
- Here it is with the failing subgoal marked.
-
- integers([A|B]) :-
- integer(A),
- FAILS==>integers(B).
-
- Instantiated, this subgoal is integers([]).
-
- GOING DOWN A LEVEL,
- The goal at this level is integers([]) which failed.
- Clause 1 of integers / 1 failed.
- Here it is with the failing subgoal marked.
-
- integers([]) :-
- !,
- FAILS==>fail.
- Instantiated, this subgoal is fail.
- GOING DOWN A LEVEL,
- You deliberately called the predicate 'fail'.
- -- ( end of this particular possible bug explanation ) --
-
- LISTING 4.
- Finding information about the current level bug.
- % reports what has happened at current level,
- % produces a report frame
- current_level_bug_report( Goal,
- Current_level_report) :-
- % see why each clause of the Goal predicate failed
- clause_reports( Goal,
- Clause_report_list) ,!,
- % produce a bug report from the clause info
- current_level_bug_report_hlpr( Goal,
- Clause_report_list,
- Current_level_report) .
-
- LISTING 5.
- Reporting clause failures.
-
- % maps a Goal into a list of reports on what happened when you
- % tried to satisfy the Goal using the various clauses of the
- % Goal's predicate
- clause_reports( Goal, Clause_report_list) :-
- % get functor and arity from Goal
- functor( Goal, Functor, Arity), !,
- % get generalized rule head
- functor( Head, Functor, Arity), !,
- % get clauses which have this functor as head
- findall( X,
- ( clause( Head, Body),
- X = ( Head :- Body)),
- Clauses), !,
- % clean up database
- retractall(zzz_current_goal( _ )),
- % store goal to protect it from unification
- asserta( zzz_current_goal( Goal)),
- gen_clause_reports( Clauses, 1, Clause_report_list),
- % clean up database
- retractall(zzz_current_goal( _ )).
-
- LISTING 6.
- Clause-level bug reporting.
-
- clause_report_hlpr( Clause, Report ):-
- % get fresh copy of Goal, unaffected by any unifications
- % done in computing previous clause reports
- call( zzz_current_goal( Goal)),
- % get head of rule
- Clause = ( Head :- Body), !,
- % if the Head matches the Goal...
- ( Head = Goal,
- % stay with this branch
- !,
- % save the fact that the heads match
- Report0 = [ head_matched : true],
- % collect more info about trying the clause body
- clause_report_hlpr_on_body( Body, 1, Report0, Report)
- ;
- % else if Head does not match Goal
- !,
- % report out that fact
- Report = [ head_matched : fail ]).
- /** clause_report_hlpr_on_body finds info on where the body of a
- rule fails **/
- % debug rule
- clause_report_hlpr_on_body( Body , _, Report, _ ) :-
- clause_level_trace([$e clause_report_hlpr_on_body, Body = $,
- Body,
- $ Report = $, Report ]),
- fail.
- % quit when a failure is reported
- clause_report_hlpr_on_body( _ , _, Report, Report) :-
- clause_has_already_failed( Report ), !.
- % increment cut counts for cut terms
- clause_report_hlpr_on_body( ( Term , Rest), N, Report0, Report) :-
- Term == !,
- !,
- increment_cut_count( Report0, Report1),
- N1 is N+1,
- clause_report_hlpr_on_body( Rest, N1, Report1, Report).
- % recurse on success with next term
- clause_report_hlpr_on_body( ( Term , Rest), N, Report0, Report) :-
- call( Term),
- !,
- N1 is N+1,
- clause_report_hlpr_on_body( Rest, N1, Report0, Report).
- % report term failure
- clause_report_hlpr_on_body( ( Term , _ ), N, Report0, Report) :-
- !,
- Term_report = [ result : fail,
- failing_subgoal_number : N,
- failing_subgoal : Term ],
- frame_unify( Term_report,
- Report0,
- Report ) .
- % increment cut counts for final cut terms
- clause_report_hlpr_on_body( !, _, Report0, Report) :-
- !,
- increment_cut_count( Report0, Report ).
- % report success for clause if last term succeeds
- clause_report_hlpr_on_body( Term , N, Report0, Report) :-
- call( Term),
- !,
- Term_report = [ result : success,
- number_of_subgoals : N],
- frame_unify( Term_report,
- Report0,
- Report ) .
- % report term failure
- clause_report_hlpr_on_body( Term , N, Report0, Report) :-
- !,
- Term_report = [ result : fail,
- failing_subgoal_number : N,
- failing_subgoal : Term ],
- frame_unify( Term_report,
- Report0,
- Report ) .
-
- LISTING 7.
- Example of clause-report analysis.
-
- % If clause report list is empty,
- % no rules are defined
- current_level_bug_report_hlpr(
- Goal, % the current goal
- [], % the list of clause reports
- % the generated current level bug report
- [goal_report(
- [ call : Goal,
- result : fail,
- reason :
- no_clauses_defined])]) :- !.
- % if only 1 head matches , look in there
- current_level_bug_report_hlpr( Goal,
- Clause_report_list,
- Bug_report) :-
- findall( Clause,
- ( memb( Clause, Clause_report_list),
- frame_slot_val(head_matched, Clause, true)),
- [ Head_matched ]),
- bug_report_on_clause( Head_matched, Bug_report0 ),
- frame_unify( [ call : Goal], Bug_report0, Bug_report1),
- frame_info( Bug_report1, _, Slots),
- Bug_report = [goal_report( Slots)], !.
- bug_report_on_clause( Clause_report , Bug_report) :-
- frame_slot_val( failing_subgoal, Clause_report, Failure),
- remove_if_slot( head_matched,
- Clause_report ,
- What_we_need ) ,
- frame_info( What_we_need , _, Bug_report ).
- 1
- LISTING 8.
- Backtracking version of member.
-
- memb(H,[H|_]).
- memb(H,[_|T]) :- memb(H,T).
-
- /* Special thanks to Andre Vellino at Bell Northern Research in Ottawa,
- ON, for showing me how useful this simple predicate can be. */
- anks to Andre Vellino