[comp.lang.scheme] function tracing in Scheme

jaffer@zurich.ai.mit.edu (Aubrey Jaffer) (04/26/91)

Here is code for tracing functions which should work in any scheme.
If you have macros on you system you can add some syntactic sugar and
finish the job.  And yes, it can trace itself.  And no, it doesn't get
screwed up if you trace functions it uses.

;;;; Utility functions for debugging in Scheme.

;;; TRACEF REALLY NEEDS A `PRINT ANYTHING ON ONE LINE' ROUTINE.  DOES
;;; SOMEONE CARE TO WRITE IT?

;;; to TRACE type
;;; (set! <symbol> (tracef <symbol>)) or
;;; (set! <symbol> (tracef <symbol> '<symbol>)) or
;;; (define <symbol> (tracef <function>)) or
;;; (define <symbol> (tracef <function> '<symbol>))

;;; to UNTRACE type
;;; (set! <symbol> (untracef <symbol>))

(define tracef
  (let ((null? null?)			;These bindings are so that
	(not not)			;tracef will not trace parts
	(car car)			;of itself.
	(cdr cdr)
	(eq? eq?)
	(write write)
	(display display)
	(newline newline)
	(apply apply)
	(for-each for-each))
    (lambda (function . optname)
      (let ((name (if (null? optname) function (car optname))))
	(lambda args
	  (cond ((and (not (null? args))
		      (eq? (car args) '**special-untrace-object**)
		      (null? (cdr args)))
		 function)
		(else
		 (display "CALL [")
		 (write name)
		 (display #\ )
		 (for-each (lambda (x) (write x) (display #\ )) args)
		 (display "]")
		 (newline)
		 (let ((ans (apply function args)))
		   (display "RETURNED [")
		   (write name)
		   (display " ==> " )
		   (write ans)
		   (display "]")
		   (newline)
		   ans))))))))

;;; the reason I use a symbol for **special-untrace-object** is so
;;; that functions can still be untraced if this file is read in twice.

(define (untracef function)
  (function '**special-untrace-object**))

markf@zurich.ai.mit.edu (Mark Friedman) (04/27/91)

In article <JAFFER.91Apr26120238@kleph.ai.mit.edu> jaffer@zurich.ai.mit.edu (Aubrey Jaffer) writes:

   Here is code for tracing functions which should work in any scheme.
   If you have macros on you system you can add some syntactic sugar and
   finish the job.  And yes, it can trace itself.  And no, it doesn't get
   screwed up if you trace functions it uses.

   ;;;; Utility functions for debugging in Scheme.

   ;;; to TRACE type
   ;;; (set! <symbol> (tracef <symbol>)) or
   ;;; (set! <symbol> (tracef <symbol> '<symbol>)) or
   ;;; (define <symbol> (tracef <function>)) or
   ;;; (define <symbol> (tracef <function> '<symbol>))

   ;;; to UNTRACE type
   ;;; (set! <symbol> (untracef <symbol>))

   [code for trace and untrace omitted]

This is all well and good, but only useful for procedures that are
referenced by name (and it only traces them where they are referenced
by that name, and you lose eq-ness for traced procedures). You need
some hackery in the interpreter and/or compiler to make tracing work
for arbitrary procedures.

   ;;; TRACEF REALLY NEEDS A `PRINT ANYTHING ON ONE LINE' ROUTINE.  DOES
   ;;; SOMEONE CARE TO WRITE IT?

Unless I misunderstand what you mean I think that the following will
do it.

(define (display-anything-on-one-line . things)
  (if (not (null? things))
      (let loop ((things things))
	(if (null? things)
	    (newline)
	    (begin
	      (display (car things))
	      (loop (cdr things)))))))

-Mark
--

Mark Friedman
MIT Artificial Intelligence Lab
545 Technology Sq.
Cambridge, Ma. 02139

markf@zurich.ai.mit.edu

jaffer@zurich.ai.mit.edu (Aubrey Jaffer) (04/27/91)

From <MARKF.91Apr26151741@montreux.ai.mit.edu>:
> This is all well and good, but only useful for procedures that are
> referenced by name (and it only traces them where they are referenced
> by that name, and you lose eq-ness for traced procedures). You need

You are right about eq-ness when the function was grabbed before being
traced but tracef works for unnamed procedures.

> ((tracef (lambda (x) (cons x x))) 9)
CALL [#[CLOSURE (x) (cons x x)] 9 ]
RETURNED [#[CLOSURE (x) (#@cons #@0+0 #@0+0)] ==> (9 . 9)]
;Evaluation took 0 mSec (0 in gc) 24 cons work
(9 . 9)

> some hackery in the interpreter and/or compiler to make tracing work
> for arbitrary procedures.
> 
>    ;;; TRACEF REALLY NEEDS A `PRINT ANYTHING ON ONE LINE' ROUTINE.  DOES
>    ;;; SOMEONE CARE TO WRITE IT?
> 
> Unless I misunderstand what you mean I think that the following will
> do it.
>      ... code deleted ...
No.  What I meant is a function which prints in such a way as to show
as much top-level structure as possible while fitting in one line.  It
replaces too large sub-structures with ... or & in the printed output.

markf@zurich.ai.mit.edu (Mark Friedman) (04/29/91)

In article <JAFFER.91Apr26223409@kleph.ai.mit.edu> jaffer@zurich.ai.mit.edu (Aubrey Jaffer) writes:

   From <MARKF.91Apr26151741@montreux.ai.mit.edu>:
   > This is all well and good, but only useful for procedures that are
   > referenced by name (and it only traces them where they are referenced
   > by that name, and you lose eq-ness for traced procedures). You need

   You are right about eq-ness when the function was grabbed before being
   traced but tracef works for unnamed procedures.

   > ((tracef (lambda (x) (cons x x))) 9)
   CALL [#[CLOSURE (x) (cons x x)] 9 ]
   RETURNED [#[CLOSURE (x) (#@cons #@0+0 #@0+0)] ==> (9 . 9)]
   ;Evaluation took 0 mSec (0 in gc) 24 cons work
   (9 . 9)

What I meant was that you can't trace the unnamed procedure and have
the procedure be side-effected so that all uses of the procedure will
be traced.

   > some hackery in the interpreter and/or compiler to make tracing work
   > for arbitrary procedures.
   > 
   >    ;;; TRACEF REALLY NEEDS A `PRINT ANYTHING ON ONE LINE' ROUTINE.  DOES
   >    ;;; SOMEONE CARE TO WRITE IT?
   > 
   > Unless I misunderstand what you mean I think that the following will
   > do it.
   >      ... code deleted ...
   No.  What I meant is a function which prints in such a way as to show
   as much top-level structure as possible while fitting in one line.  It
   replaces too large sub-structures with ... or & in the printed output.

Oh. Never mind.

-Mark
--

Mark Friedman
MIT Artificial Intelligence Lab
545 Technology Sq.
Cambridge, Ma. 02139

markf@zurich.ai.mit.edu