At 10:28 Uhr -0500 04.01.2006, Marc Feeley wrote:
It is possible using undocumented procedures. Here's what you want:
Thank you.
I'm planning to change this so that the default user-interrupt- handler behaves like exceptions, i.e. the default will be to terminate the program after displaying "*** INTERRUPTED IN ...".
The default for unix programs is that SIGINT makes them terminate *and deliver that fact to the parent* (through wait(2) the parent can know if the child terminated because of a signal and which one it was). If you trap SIGINT, then afaik the only way to make the parent know we are terminating because of a signal is to remove our signal handler and then killing ourselves again. This poses the question as to why a signal handler has been installed in the first place. I think that printing a message and exiting with an error code is a nonstandard and thus suboptimal solution, and that not installing signal handlers at all unless really necessary would be, in principle, a better solution. (I'm mainly coming from perl, which works that way.) I don't want to suggest to give this a high priority though and also have never really programmed on non-unix systems.
With the runtime option "-:d" the system will instead start a REPL. With the runtime option "-:d0" the program will terminate silently. However, when inside a REPL (such as the one normally started in interactive mode), a SIGINT will start a nested REPL.
That makes sense to me.
(*) that leads to another question I've been wondering about: parameterize doesn't accept procedures which aren't parameters (it checks their type). This makes the above suggestion impossible to be implement transparently of course, since it would require running code other than just for setting the dynamic value (**).
I don't understand what you mean.
Here's a normal parameter p1, and a self-written parameter like function p2 which has the side effect of something like initializing signal setup if not done already:
(define p1 (make-parameter #f))
(define pseudo-signal-handler-hook #f) (define p2 (let ((absent (gensym)) (value #f)) (lambda (#!optional (newvalue absent)) (if (eq? newvalue absent) value (begin (if (not pseudo-signal-handler-hook) (set! pseudo-signal-handler-hook (lambda () (display "hello world\n")))) (set! value newvalue))))))
; > (p1) ; #f ; > (p1 "hello") ; > (p1) ; "hello" ; > (p2) ; #f ; > pseudo-signal-handler-hook ; #f ; > (p2 "world") ; > (p2) ; "world" ; > pseudo-signal-handler-hook ; #<procedure #2 pseudo-signal-handler-hook> ; > (#2) ; hello world
; > (begin (parameterize ((p1 "a")) (display (p1))(newline)) (display (p1))(newline)) ; a ; #f ; > (begin (parameterize ((p2 "a")) (display (p2))(newline)) (display (p2))(newline)) ; *** ERROR IN (console)@3.8 -- PARAMETER expected ; 1>
The problem is that my side-effecting pseudo parameter cannot be transparently used with parameterize. It occured to me as an unnecessary drawback when I first realized that parameters were procedures but procedures can't be parameters. I did assume parameterize were implemented about like this (e.g. querying the old value, storing in lexical context, setting new value with dynamic-wind):
; (let ((#:g10 (p2))) ; (dynamic-wind ; (lambda () (p2 "a")) ; (lambda () (display (p2)) (newline)) ; (lambda () (p2 #:g10))))
(let ((#:var2 "a")) (let ((#:swap4 (lambda () (let ((#:tmp3 (p2))) (p2 #:var2) (set! #:var2 #:tmp3))))) (dynamic-wind #:swap4 (lambda () (display (p2)) (newline)) #:swap4)))
; as generated by this macro:
(define-macro (my-parameterize bindings . body) (let* ((b-alist (map (lambda (l) (cons l (gensym 'var))) bindings)) (b->var (lambda (l) (cdr (assoc l b-alist)))) (b->name car) (b->init cadr) (tmp (gensym 'tmp)) (swap (gensym 'swap))) `(let ,(map (lambda (l) (list (b->var l) (b->init l))) bindings) (let ((,swap (lambda () ,@ (map (lambda (l) `(let ((,tmp (,(b->name l)))) (,(b->name l) ,(b->var l)) (set! ,(b->var l) ,tmp))) bindings)))) (dynamic-wind ,swap (lambda () ,@ body) ,swap)))))
I know this implementation of parameterize has a problem though: dynamic-wind is not safe when using exceptions. Why? I find this especially strange considering that I thought with-exception-catcher was implemented using continuations.
Which other reasons are there for implementing parameters differently? Performance or semantics? I guess the above implementation would be rather slow. I've taken a cursory look at the srfi-39 document and discussion archive, but most of it is over my head right now, I'll reread later.
So, it seems that the "most natural way" of how parameterize would be implemented is not the best and thus I shouldn't expect to be able to put callbacks into a supposedly lowlevel dynamic bindings mechanism.
What's the reason for this restriction?
Parameters are special procedures that contain a key. This key is used to lookup the binding of the parameter. The machinery is quite complex (see _thread.scm).
I'll reread it later.
((**) without this, the user would have to run some (user-interrupt- initialize!) hook first -- at least, that might be better for thread safety?)
Thanks, Christian.