joe@erix.ericsson.se (Joe Armstrong) (06/10/91)
Could sombody who understands these things kindly explain how to do the equivalent of 'catch' and 'throw' in scheme?? - can one use call/cc for such operations? - if so how? Why? I want to do a non local return from a deep recursion when I dedect an error but not go to all the trouble of unwinding the stack and building a lot of stuff which I'm going to junk anyway. Joe Armstrong.
jinx@zurich.ai.mit.edu (Guillermo J. Rozas) (06/11/91)
In article <1991Jun10.124127.17926@eua.ericsson.se> joe@erix.ericsson.se (Joe Armstrong) writes:
Path: ai-lab!mintaka!bloom-beacon!eru!hagbard!sunic!ericom!eua.ericsson.se!erix.ericsson.se!joe
From: joe@erix.ericsson.se (Joe Armstrong)
Newsgroups: comp.lang.scheme
Date: 10 Jun 91 12:41:27 GMT
Sender: news@eua.ericsson.se
Organization: Ellemtel Telecom Systems Labs, Stockholm, Sweden
Lines: 9
Nntp-Posting-Host: gordons.eua.ericsson.se
Could sombody who understands these things kindly explain how
to do the equivalent of 'catch' and 'throw' in scheme?? -
can one use call/cc for such operations? - if so how?
Why? I want to do a non local return from a deep recursion
when I dedect an error but not go to all the trouble of unwinding the
stack and building a lot of stuff which I'm going to junk anyway.
Joe Armstrong.
call-with-current-continuation (I hate the cutesy call/cc) can be
considered a generalization of catch and throw, although it has an
apparently more confusing interface.
You can easily rewrite programs that use catch and throw to use
call-with-current-continuation instead, but if you find the
catch/throw model more easily understood, we can define catch and
throw in terms of it.
Assuming that there are no CL-style multiple values (or that you are
not using them), and that the program will not error or be
interrupted, we can define catch an throw as macros in the following
way
(define-macro (catch tag . forms)
`(catch-proc
,tag
(lambda ()
,@forms)))
(define-macro (throw tag result-form)
`(throw-proc
,tag
(lambda ()
,result-form)))
where the missing procedures are defined as
(define *catch-tags* '())
(define (catch-proc tag thunk)
(let ((saved-tags *catch-tags*))
(let ((value
(call-with-current-continuation
(lambda (cont)
(set! *catch-tags*
(cons (cons tag cont)
saved-tags))
(thunk)))))
(set! *catch-tags* saved-tags)
value)))
(define (throw-proc tag thunk)
(let ((pair (assq tag *catch-tags*)))
(if (not pair)
(error "throw: No such tag" tag)
((cdr pair) (thunk)))))
If you are using CL-style multiple values, and have fluid-let to boot,
then you can replace the definitions of catch-proc and throw-proc with
the following:
(define (catch-proc tag thunk)
(apply values ; (values-list (call...))
(call-with-current-continuation
(lambda (cont)
(fluid-let ((*catch-tags*
(cons (cons tag cont)
*catch-tags*)))
(with-values thunk list)))))) ; (multiple-values-list (thunk))
(define (throw-proc tag thunk)
(let ((pair (assq tag *catch-tags*)))
(if (not pair)
(error "throw: No such tag" tag)
(with-values thunk ; (multiple-value-call #'(lambda all ...)
(lambda all ; (thunk))
((cdr pair) all))))))
kend@data.UUCP (Ken Dickey) (06/11/91)
joe@erix.ericsson.se (Joe Armstrong) writes: >Could sombody who understands these things kindly explain how >to do the equivalent of 'catch' and 'throw' in scheme?? - >can one use call/cc for such operations? - if so how? Just use your local syntax system to define the syntactic transformation: (catch . <body>) --> (call/cc (throw) <body>) Then you can (throw <exp>) from within <body>. -Ken Dickey kend@data.uucp
janssen@parc.xerox.com (Bill Janssen) (06/11/91)
In article <JINX.91Jun10165336@chamarti.ai.mit.edu> jinx@zurich.ai.mit.edu (Guillermo J. Rozas) writes: > Assuming that there are no CL-style multiple values (or that you are > not using them), and that the program will not error or be > interrupted, we can define catch an throw as macros in the following ...assuming you have macros :-) -- Bill Janssen janssen@parc.xerox.com (415) 494-4763 Xerox Palo Alto Research Center 3333 Coyote Hill Road, Palo Alto, California 94304
raible@nas.nasa.gov (Eric Raible) (06/12/91)
In article <502@data.UUCP> kend@data.UUCP (Ken Dickey) writes:
From: kend@data.UUCP (Ken Dickey)
Newsgroups: comp.lang.scheme
Date: 10 Jun 91 23:20:22 GMT
Organization: Microcosm, Beaverton, OR
Just use your local syntax system to define the syntactic transformation:
(catch . <body>) --> (call/cc (throw) <body>)
Then you can (throw <exp>) from within <body>.
-Ken Dickey kend@data.uucp
Don't you mean this:
(catch . <body>) --> (call/cc (lambda (throw) <body>))
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (06/13/91)
In article <1991Jun10.124127.17926@eua.ericsson.se> joe@erix.ericsson.se (Joe Armstrong) writes: > Could sombody who understands these things kindly explain how > to do the equivalent of 'catch' and 'throw' in scheme?? - > can one use call/cc for such operations? - if so how? In article <JINX.91Jun10165336@chamarti.ai.mit.edu>, jinx@zurich.ai.mit.edu (Guillermo J. Rozas) explained how to implement catch and throw on top of call/cc. I suggest that it is simpler to use call-with-current-continuation directly. For example, on p80 of Dybvig's book, we find "Here is a more practical example, showing the use of call/cc to provide a nonlocal exit from a loop. (define member (lambda (x ls) (call/cc (lambda (break) (do ((ls ls (cdr ls))) ((null? ls) #f) (if (equal? x (car ls)) (break ls))))))) " (I have corrected two gratuitous incompatibilities with the standard.) In general, the picture is (call-with-current-continuation (lambda (escape-function) ;; any amount of your code goes here. ;; When you want to return from the entire construct ;; with value x, just call (escape-function x) ;; and that can go anywhere you like. )) The advantage of catch and throw is that a procedure can "throw" to a "catch" which doesn't *lexically* enclose it. -- Q: What should I know about quicksort? A: That it is *slow*. Q: When should I use it? A: When you have only 256 words of main storage.
davis@barbes.ilog.fr (Harley Davis) (06/13/91)
In article <RAIBLE.91Jun12103833@wk43.nas.nasa.gov> raible@nas.nasa.gov (Eric Raible) writes: In article <502@data.UUCP> kend@data.UUCP (Ken Dickey) writes: Just use your local syntax system to define the syntactic transformation: (catch . <body>) --> (call/cc (throw) <body>) Then you can (throw <exp>) from within <body>. -Ken Dickey kend@data.uucp Don't you mean this: (catch . <body>) --> (call/cc (lambda (throw) <body>)) In any case, this implements BLOCK and RETURN-FROM, not CATCH and THROW. CATCH/THROW requires a dynamic scope for the THROW procedure, which is difficult (!) to implement just using CALL/CC. The other proposed solution was correct, though, if not very efficient. -- Harley Davis -- ------------------------------------------------------------------------------ nom: Harley Davis ILOG S.A. net: davis@ilog.fr 2 Avenue Gallie'ni, BP 85 tel: (33 1) 46 63 66 66 94253 Gentilly Cedex, France
markf@zurich.ai.mit.edu (Mark Friedman) (06/14/91)
In article <6246@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: In article <1991Jun10.124127.17926@eua.ericsson.se> joe@erix.ericsson.se (Joe Armstrong) writes: > Could sombody who understands these things kindly explain how > to do the equivalent of 'catch' and 'throw' in scheme?? - > can one use call/cc for such operations? - if so how? In article <JINX.91Jun10165336@chamarti.ai.mit.edu>, jinx@zurich.ai.mit.edu (Guillermo J. Rozas) explained how to implement catch and throw on top of call/cc. I suggest that it is simpler to use call-with-current-continuation directly. This may be true, but I think the point was that Joe Armstrong knew what catch and throw did and wanted to see how they could be implemented in terms of call-with-current-continuation. The advantage of catch and throw is that a procedure can "throw" to a "catch" which doesn't *lexically* enclose it. I can apply any escape procedure (the packaged-up form of a continuation) anywhere. The fact that catch and throw maintain a dynamic mapping of catch-tags to continuations can be convenient though. The next version of MIT Scheme will have Common Lisp style restarts, which provide that convenience plus the ability to inspect the mappings and to see dynamically shadowed mappings. -Mark -- Mark Friedman MIT Artificial Intelligence Lab 545 Technology Sq. Cambridge, Ma. 02139 markf@zurich.ai.mit.edu