home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / lifeos2.zip / LIFE-1.02 / TOOLS / DEBUG.DOC < prev    next >
Text File  |  1996-06-04  |  8KB  |  361 lines

  1. #    $Id: Debug.doc,v 1.2 1994/12/08 23:46:45 duchier Exp $    
  2. Richard Meyer                            June 16th 1993
  3.  
  4.  
  5.  
  6.  
  7.  
  8.             A Simple Debugger for LIFE
  9.             ==========================
  10.  
  11.  
  12.  
  13.  
  14.  
  15. This document describes a small debugging module for LIFE. It works both on
  16. predicates and functions, although support for predicates is somewhat better
  17. than that for functions. The debugger works by reading then re-writing the
  18. corresponding clauses, this is closer to placing spy-points than systematic
  19. debugging.
  20.  
  21.  
  22.  
  23.  
  24. 1- Predicates: the extended box model:
  25. --------------------------------------
  26.  
  27. The flow of execution for each predicate is modelled as a box (as is often the
  28. case with Prolog debuggers) however with this debugger the box isn't quite
  29. black and it is possible to have a look at what's going on inside.
  30.  
  31. Whenever the predicate is called, the box is entered via the 'CALL' stream, the
  32. first clause is selected and the goals in the clause are called in succession.
  33. If the predicate succeeds, the system exits through the 'SUCCess' stream. If
  34. the predicate is forces to retry, the system enters the 'REDO' stream and
  35. either re-enters one of the goals' 'REDO' boxes or tries the next clause. If
  36. there are no more clauses, the system exits via the 'FAIL' stream.
  37.  
  38. This is what it looks like:
  39.  
  40.             PREDICATE (in its box)
  41.              +-------------------+
  42.              |                   |
  43.  CALL clause #1 ------->GOAL#1.1     |
  44.              |    GOAL#1.2,     |
  45.              |    GOAL#1.3 etc...    ---> clause #1 SUCCess
  46.              |                   |
  47.              |  GOAL#2.1, <--------- REDO clause #2
  48.              |    GOAL#2.2,     |
  49.              |    GOAL#2.3 etc...    ---> clause #2 SUCCess
  50.              |                   |
  51.              |          <--------- REDO clause #3 etc...
  52.              |                   |
  53.  FAIL <-----------------
  54.              |                   |
  55.              +-------------------+
  56.  
  57.  
  58. The debugger allows you to monitor movement to and from the box as well as
  59. within it.
  60.  
  61.  
  62.  
  63. 2- Functions:
  64. -------------
  65.  
  66. A similar approach is taken, although currying and residuation are NOT
  67. implemented account (unfortunately).
  68.  
  69. This is what function calls look like:
  70.  
  71. CALL --> match PATTerns --> EVALuate value --> such-that GOALs --> SUCCess
  72.      --> RESIduate--^
  73.      --> CURRy
  74.  
  75.  
  76.  
  77. 3- Using the debugger:
  78. ----------------------
  79.  
  80. The debugger is implemented as a module which must be loaded and opened:
  81.  
  82.     > import("debug.lf")?
  83.  
  84. One the entire application has been loaded, it is possible to choose which
  85. predicates will be debugged.
  86.  
  87.     > debug(Name,Level,Verbose)?
  88.  
  89. Where 'Name' is the name of the function or predicate to debug, 'Level' may be
  90. 'fail', 'clause' or 'goal' and 'Verbose' is 'true' or 'false'. The default mode
  91. is 'debug(2=>clause,3=>true)'.
  92.  
  93.  
  94. Debugging code may be removed and the original rules restored using:
  95.  
  96.     > undebug(Name)?
  97.  
  98. You may invoke 'debug' several times over the same predicate or function with
  99. different level or verbose values. The original clauses will be used.
  100.  
  101.  
  102.  
  103. 4- Using the different levels:
  104. ------------------------------
  105.  
  106. The 'Level' allows you to determine how much output (and overhead) you want to
  107. get from Wild-LIFE.
  108.  
  109. For predicates:
  110.  
  111.     o 'fail' mode: reports FAIL only.
  112.     This is minimalistic but very useful for finding out where a program
  113.     fails. This mode also puts minimal overhead on the interpretrer. Use
  114.     it on predicates which should never fail.
  115.  
  116.     o 'clause' mode: reports CALL, SUCC, REDO, CUT! and FAIL.
  117.     This is the normal mode (a slight extension of Prolog's model).
  118.  
  119.     o 'goal' mode: reports CALL, GOAL, SUCC, REDO, CUT! and FAIL
  120.     This gives detailed information as to which goal in the predicate is
  121.     being called. Use this sparingly as this can get quite wordy.
  122.  
  123.  
  124. For functions:
  125.  
  126.     o 'fail' mode: reports FAIL only.
  127.  
  128.     o 'clause' mode: reports EVAL, SUCC, FAIL.
  129.  
  130.     o 'goal' mode: reports PATT, EVAL, GOAL, SUCC, FAIL
  131.  
  132.  
  133.  
  134. 5- An example predicate:
  135. ------------------------
  136.  
  137. First, load all the clauses of your program, in this example we have:
  138.  
  139.     p(X) :- X={one;two}.
  140.     p(three).
  141.     p(X) :- Y/3=X,Y=2*Z,Z=6.
  142.     p(X) :- X=five
  143.         ;
  144.         X=six.
  145.     p(Y) :- p(X),!,Y={'VIII';'IX'}.
  146.     p('0x1010').
  147.  
  148.     app([H|T],L,[H|R]) :- !,app(T,L,R).
  149.     app([],L,L).
  150.  
  151.  
  152. Then, load the debugging library (don't forget to open the module):
  153.  
  154.     > import("debug.lf")?
  155.     *** File "Tools/debug.lf" loaded
  156.  
  157.     *** Yes
  158.  
  159.  
  160. Next, decide which predicates to debug:
  161.  
  162.     > debug(p,goal)?
  163.     -SPY--> p: level=goal, verbose=true
  164.  
  165.     *** Yes
  166.  
  167.  
  168. And now, just use the predicate normally:
  169.  
  170.     > p(X),nl,write("X=",X),nl,fail ?
  171.     -CALL-> p(@): entry call
  172.     -GOAL-> p#1.1: @ = one
  173.     -SUCC-> p#1: succeeds
  174.     
  175.     X=one
  176.     
  177.     p#1.1: @ = two
  178.     -SUCC-> p#1: succeeds
  179.     
  180.     X=two
  181.     
  182.     -REDO-> p: try clause #2
  183.     -GOAL-> p#2.1: succeed
  184.     -SUCC-> p#2: succeeds
  185.     
  186.     X=three
  187.     
  188.     -REDO-> p: try clause #3
  189.     -GOAL-> p#3.1: real~ = @
  190.     -GOAL-> p#3.2: real~ = real~  % Sub-goal #2 of clause #3 for 'p'
  191.     -GOAL-> p#3.3: real~ = 6
  192.     -SUCC-> p#3: succeeds
  193.     
  194.     X=4
  195.     
  196.     -REDO-> p: try clause #4
  197.     -GOAL-> p#4.1: @ = five
  198.     -SUCC-> p#4: succeeds
  199.     
  200.     X=five
  201.     
  202.     -REDO-> p#4: retry disjunction
  203.     -GOAL-> p#4.1: @ = six
  204.     -SUCC-> p#4: succeeds
  205.     
  206.     X=six
  207.     
  208.     -REDO-> p: try clause #5
  209.     -GOAL-> p#5.1: p(@)
  210.     -CALL-> p(@): entry call
  211.     -GOAL-> p#1.1: @ = one
  212.     -SUCC-> p#1: succeeds
  213.     -CUT!-> p#5.2: cut!
  214.     -GOAL-> p#5.3: @ = VIII
  215.     -SUCC-> p#5: succeeds
  216.     
  217.     X=VIII
  218.     
  219.     p#5.3: @ = IX
  220.     -SUCC-> p#5: succeeds
  221.     
  222.     X=IX
  223.     
  224.     -FAIL-> p#5: fails and alternatives cut
  225.     
  226.     *** No
  227.  
  228.     >
  229.  
  230. Now let's debug 'app' at a less verbose level:
  231.  
  232.     > debug(app,clause,false)?
  233.     -SPY--> app: level=clause, verbose=false
  234.     
  235.     *** Yes
  236.     --1> 
  237.     
  238.     *** No
  239.     > app(A,B)?
  240.     -CALL-> app: entry call
  241.     -CUT!-> app#1: cut!
  242.     -CALL-> app: entry call
  243.     -CUT!-> app#1: cut!
  244.     -CALL-> app: entry call
  245.     -CUT!-> app#1: cut!
  246.     -CALL-> app: entry call
  247.     -CUT!-> app#1: cut!        % Oops looping.
  248.     -CALL-> app: entry call
  249.     -CUT!-> app#1: cut!
  250.     -CALL-> app: entry call
  251.     -CUT!-> app#1: cut!
  252.     -CALL-> app: entry call
  253.     -CUT!-> app#1: cut!
  254.     -CALL-> app: entry call^C-CUT!-> 
  255.     *** Command (q,c,a,s,t,h)?a
  256.     
  257.     *** Abort
  258.     > app([1,2,3],R,[1,2,3,4,5,6])?
  259.     -CALL-> app: entry call
  260.     -CUT!-> app#1: cut!
  261.     -CALL-> app: entry call
  262.     -CUT!-> app#1: cut!
  263.     -CALL-> app: entry call
  264.     -CUT!-> app#1: cut!
  265.     -CALL-> app: entry call
  266.     -REDO-> app: try clause #2
  267.     -SUCC-> app#2: succeeds
  268.     -SUCC-> app#1: succeeds
  269.     -SUCC-> app#1: succeeds
  270.     -SUCC-> app#1: succeeds
  271.     
  272.     *** Yes
  273.     R = [4,5,6].
  274.     --1> ;
  275.     -FAIL-> app: fails
  276.     -FAIL-> app#1: fails and alternatives cut
  277.     -FAIL-> app#1: fails and alternatives cut
  278.     -FAIL-> app#1: fails and alternatives cut
  279.     
  280.     *** No
  281.     >
  282.  
  283.  
  284.  
  285. 6- An example function:
  286. -----------------------
  287.  
  288.     > import("debug")?
  289.     *** File "./Tools/debug.lf" loaded
  290.  
  291.     > debug(append)?
  292.     Added debugging code to function 'append': level=clause,
  293.     verbose=true, clauses=2
  294.  
  295.     *** Yes
  296.  
  297.     > 
  298.     > A=append([a,b,c],[d,e,f])?
  299.     <EVAL> append([],[d,e,f]): clause #1, result=[d,e,f]
  300.     <EVAL> append([c],[d,e,f]): clause #2, result=[c,d,e,f]
  301.     <EVAL> append([b,c],[d,e,f]): clause #2, result=[b,c,d,e,f]
  302.     <EVAL> append([a,b,c],[d,e,f]): clause #2, result=[a,b,c,d,e,f]
  303.  
  304.     *** Yes
  305.     A = [a,b,c,d,e,f].
  306.     --1> ;
  307.  
  308.     *** No
  309.  
  310.     >
  311.     > A=append([a,b,c],4)?
  312.     <FAIL> append([a,b,c],4): fails
  313.  
  314.     *** No
  315.  
  316.  
  317.  
  318. 7- Understanding how it works:
  319. ------------------------------
  320.  
  321. This debugger works by retracting your original clauses and re-writing them
  322. with additional trace and execution control instructions. Use 'listing' to
  323. examine the generated code.
  324.  
  325. All tracing is local to the clause, if alternatives are pruned using '!' at a
  326. higher level in the program, then failures and retries for the predicate being
  327. debugged will not be visible - this is a useful feature.
  328.  
  329. The use of the debugger should in no way alter the semantics of the program,
  330. however some changes will be visible:
  331.  
  332.     o using 'trace' will become (even more) difficult,
  333.  
  334.     o assert, asserta, retract and clause will NOT work correctly,
  335.  
  336.     o residuations on the calling predicate itself will be released more
  337.       frequently (very rare),
  338.  
  339.     o memory usage will be bigger, although this has been reduced as much
  340.       as possible by using local failure.
  341.  
  342.  
  343.  
  344. 8- Possible enhancements: loads!!
  345. -------------------------
  346.  
  347.     o improve support for functions:
  348.         - calls,
  349.         - currying,
  350.         - residuation.
  351.  
  352.     o deal with 'trace' mode and hide all added calls,
  353.  
  354.     o add a feature to allow source coverage monitoring,
  355.  
  356.     o add support for sorts,
  357.  
  358.     o debug an entire file,
  359.  
  360.     o write modified clauses to a file.
  361.