Marc Feeley wrote:
I am deeply impressed! You get my vote for the "Gambit debugger man of the year" award!
Thanks.
PS. I've already suggested once to add a mode to the debugger to save all continuations onto a stack. So instead of recording everything into the Emacs buffer as shown above, the continuations would be on a stack/list which could be examined, that could maybe be more efficient computation-wise and maybe offer better handling.
Can you elaborate? Which continuations do you want to save?
Every (implicit) continuation the interpreter is seeing. (All function calls.)
Example: this code
(define (test a) (println (+ (/ a 2) 3)))
would be evaluated as
(define (test_ a) (R println (R + (R / a 2) 3)))
with the following library:
(define conts '()) ;; (should be per-thread or so, too)
;; hmm using parameters doesn't work, they are tied to the dynamic env in the continuations ; (define record? (make-parameter #t)) ; (define (replay c) ; (parameterize ((record? #f)) ; (c))) ;; so using a normal global instead: (define _record? #t) (define record? (& _record?)) ;; remember, & is my thunk macro (define (replay c) (dynamic-wind (& (set! _record? #f)) c (& ;; (set! _record? #t) hehe, dynamic-wind "doesn't work" either, of course, have to leave it switched off. #!void)))
(define (addcont! c) (if (record?) (set! conts (cons c conts))))
(define (R fn . args) (call/cc (lambda (cc) (addcont! cc))) (apply fn args))
;this would be an alternative allowing to feed different values when replaying: ; (define (R fn . args) ; (call/cc (lambda (cc) ; (addcont! cc) ; (apply fn args))))
(BTW I'm surprised about the behaviour of parameterize/dynamic-wind: I expected it to behave like delay/force, e.g. to not store the environment of the creation but adopt the one of the current caller. But I think I see that's not possible or e.g. exception mechanism semantics wouldn't work etc.; but the weird consequence of this is that I don't see a thread-safe, or scoped, way to tell replays to not record continuations again. Maybe I'm not fully clear about it really myself?)
Of course there would be many continuations during normal runs, and I would suggest to offer a callback mechanism to let the user choose how he wants to keep them, examples would be a ring structure (vector) of fixed size, and maybe only keep every 100th continuation or so (requiring to step forward again up to the relevant place). Ocaml's debugger is using fork(2) for the same purpose (fork a new child every nth operation).
(BTW the link to my message I've mentioned: https://webmail.iro.umontreal.ca/pipermail/gambit-list/2006-January/000579.h...)
PS.2: Gambit shouldn't exit if ,s is entered on the toplevel. (This makes using repeated ,s dangerous since one too many and the collected data of the running interpreter is lost.)
Good point. I'll change ,s and ,l so that they prevent that from happening.
..and ,c too, actually.
Christian.