[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Tracing locally defined functions



This is a plea for Common Lisp implementers to augment their TRACE utility to
handle functions defined using FLET and (especially!) LABELS.  For example,
here is a recursive definition of FACTORIAL with argument checking that uses
LABELS to define a recursively invoked helper function:

(defun FACTORIAL (n)
  (check-type n (integer 0 *))
  (labels
    ((factorial-helper (n)
      (cond ((zerop n) 1)
            (t (* n (factorial-helper (- n 1)))))))
    (factorial-helper n)))


If I wanted to trace factorial and factorial-helper, I would at least hope
that I could add the following expression to the function definition:

(defun FACTORIAL (n)
  (check-type n (integer 0 *))
  (labels
    ((factorial-helper (n)
      (cond ((zerop n) 1)
            (t (* n (factorial-helper (- n 1)))))))
    (when (member 'factorial (trace) :TEST #'eq)     ; <---
      (trace 'factorial-helper))                     ; <---
    (factorial-helper n)))

The trace of factorial-helper is initialized within the scope of the LABELS
special form, conditionally based on the trace status of the enclosing
factorial function.  Once I've completed debugging, the clause would be
removed.

I believe this ``patch'' is slightly better than avoiding LABELS until all
debugging is complete, but the technique is quite ugly.


A better solution would have implementers augment TRACE with the ability to
trace locally defined functions that are defined within a function:

(TRACE factorial :LOCALLY-DEFINED-FUNCTIONS t)

where TRACE would be smart enough to also trace any functions defined by FLET
and LABELS.  Specific functions might also be an option:

(TRACE factorial :LOCALLY-DEFINED-FUNCTIONS '(factorial-helper)).

One means of implementing such an extension to TRACE would have the LABELS
and FLET special forms check at initialization time whether the functions
they are defining are to be traced.  (I would be satisifed if this check was
only performed for interpreted code.)  When factorial is encapsulated, the
information that factorial-helper should also be traced when it is defined
would be stored for later use by LABELS.  LABELS would create the local
function and also encapsulate it for TRACE.  Then the body of the LABELS
would be evaluated.


Without the ability to trace functions defined by FLET and LABELS, these
forms loose much of their attractiveness--especially to novice programmers.
I consider the definition of factorial using LABELS to be a good example
of Common Lisp programming style, but without the ability to trace its
behavior it is difficult to recommend such programming style to beginners.

Does anyone's implementation of TRACE handle LABELS or FLET?


-- Dan Corkill