133 lines
3.6 KiB
Scheme
133 lines
3.6 KiB
Scheme
|
|
(let ()
|
|
(define k* '())
|
|
|
|
(define display-prefix
|
|
(lambda (ls t)
|
|
(unless (null? ls)
|
|
(display (if t "|" " "))
|
|
(display-prefix (cdr ls) (not t)))))
|
|
|
|
(define display-trace
|
|
(lambda (k* v)
|
|
(display-prefix k* #t)
|
|
(write v)
|
|
(newline)))
|
|
|
|
(define make-traced-procedure
|
|
(lambda (name proc)
|
|
(lambda args
|
|
(call/cf
|
|
(lambda (f)
|
|
(cond
|
|
[(memq f k*) =>
|
|
(lambda (ls)
|
|
(display-trace ls (cons name args))
|
|
(apply proc args))]
|
|
[else
|
|
(display-trace (cons 1 k*) (cons name args))
|
|
(dynamic-wind
|
|
(lambda () (set! k* (cons f k*)))
|
|
(lambda ()
|
|
(call-with-values
|
|
(lambda ()
|
|
(call/cf
|
|
(lambda (nf)
|
|
(set! f nf)
|
|
(set-car! k* nf)
|
|
(apply proc args))))
|
|
(lambda v*
|
|
(display-prefix k* #t)
|
|
(unless (null? v*)
|
|
(write (car v*))
|
|
(let f ([v* (cdr v*)])
|
|
(cond
|
|
[(null? v*) (newline)]
|
|
[else
|
|
(write-char #\space)
|
|
(write (car v*))
|
|
(f (cdr v*))])))
|
|
(apply values v*))))
|
|
(lambda () (set! k* (cdr k*))))]))))))
|
|
|
|
(define traced-symbols '())
|
|
|
|
(define trace-symbol!
|
|
(lambda (s)
|
|
(cond
|
|
[(assq s traced-symbols) =>
|
|
(lambda (pr)
|
|
(let ([a (cdr pr)] [v (top-level-value s)])
|
|
(unless (eq? (cdr a) v)
|
|
(unless (procedure? v)
|
|
(error 'trace
|
|
"the top-level value of ~s is ~s (not a procedure)"
|
|
s v))
|
|
(let ([p (make-traced-procedure s v)])
|
|
(set-car! a v)
|
|
(set-cdr! a p)
|
|
(set-top-level-value! s p)))))]
|
|
[else
|
|
(unless (top-level-bound? s)
|
|
(error 'trace "~s is unbound" s))
|
|
(let ([v (top-level-value s)])
|
|
(unless (procedure? v)
|
|
(error 'trace "the top-level value of ~s is ~s (not a procedure)"
|
|
s v))
|
|
(let ([p (make-traced-procedure s v)])
|
|
(set! traced-symbols
|
|
(cons (cons s (cons v p)) traced-symbols))
|
|
(set-top-level-value! s p)))])))
|
|
|
|
(define untrace-symbol!
|
|
(lambda (s)
|
|
(define loop
|
|
(lambda (ls)
|
|
(cond
|
|
[(null? ls) '()]
|
|
[(eq? s (caar ls))
|
|
(let ([a (cdar ls)])
|
|
(when (eq? (cdr a) (top-level-value s))
|
|
(set-top-level-value! s (car a)))
|
|
(cdr ls))]
|
|
[else (cons (car ls) (loop (cdr ls)))])))
|
|
(set! traced-symbols (loop traced-symbols))))
|
|
|
|
(primitive-set! 'make-traced-procedure make-traced-procedure)
|
|
(primitive-set! 'trace-symbol! trace-symbol!)
|
|
(primitive-set! 'untrace-symbol! untrace-symbol!))
|
|
|
|
|
|
#!eof
|
|
|
|
|
|
Try:
|
|
|
|
(trace-define fact
|
|
(lambda (n)
|
|
(if (zero? n)
|
|
1
|
|
(* n (fact (sub1 n))))))
|
|
(fact 5)
|
|
|
|
(trace-define (fact n m)
|
|
(cond
|
|
[(zero? n) m]
|
|
[else (fact (sub1 n) (* n m))]))
|
|
(fact 5 1)
|
|
|
|
|
|
(trace-define (fact n m k)
|
|
(cond
|
|
[(zero? n) (k m)]
|
|
[else (begin (fact (sub1 n) (* n m) k) 0)]))
|
|
(call/cc
|
|
(lambda (k)
|
|
(fact 6 1
|
|
(trace-lambda escape (v) (k v)))))
|
|
|
|
(trace-define (infinite-loop n)
|
|
(infinite-loop (add1 n)))
|
|
(infinite-loop 0)
|
|
|