On Thu, 2012-03-22 at 17:35 +0100, Helmut Eller wrote: > We know now that R6RS-style guard requires full continuations. I'm > not > sure what "termination-style behavior" exactly is but it sounds like > something that should NOT use full continuations. It allows for the handling of conditions outside of the influence of the calling code, which is not provided for easily by any of the other forms. While we could have chosen to remove this dependency on continuations, let me address your notes. > Therefore I think R6RS-style guard is flawed. guard could avoid full > continuations in (at least) two ways: I would respond that just because we can avoid full continuations is not, IMO, a good reason to do so. > 1. When no cond-clause matches, guard re-raises the condition in the > dynamic context of the guard form. This is similar to Java's > try-catch (+ the implicit re-throw). It is possible to do this with the current guard form explicitly, but it is not possible to go the other way easily. > 2. Evaluate the cond-tests in the dynamic environment of the original > raise. The advantage of this strategy is that it preserves the > context of the error; which is useful for debugging. This is > similar > to Common Lisp's HANDLER-CASE. This is already the semantics of normal raise or raise-continuable calls using with-exception-handler, and thus, already provided for. Guards should not generally result in any loss of error information, and usually, a guard is the wrong thing to use if you intend to halt computation, or if you want to handle continuable notifications that should return to the normal flow of things. Guards are designed for handling the cases where an error in the computation of the body prevents further reasonable execution of that body, but which does not necessarily stop the entire computation outside of the body. The guard allows one to easily provide a result to the outer context in the cases when it may be impossible to get a reasonable result from the body form. This is more difficult to accomplish in a nice way using the existing semantics of the other forms because you would have to explicitly capture a continuation around the code and then use an exception handler that called out to the continuation to get this same behavior. Even that is not quite right because you do not necessarily want the dynamic extent of the body to pollute your response in the case where the body code is no longer helpful. As an example, convincing or otherwise: (define (notify-gui-maybe msg) (define (alert) (display msg) (newline)) (guard (c [(error? c) (alert)]) (parameterize ([current-output-port gui-output-port]) (alert)))) Here, I am thinking of a custom output port that reports messages into a gui window of some application. However, there may be a problem, where perhaps the connection to the GUI is gone, or the window that the port relied on was closed by the user. We want to do the guard outside so that we can retry the (alert) using the normal output port, but if there was another message that was signalled, such as a warning, then we really want that to occur inside the the parameterize so that it can take advantage of the gui message port. Thus, this back and forth behavior is exactly what we want in this case. Moreover, using the guard form, it is very clear what we are doing here, but if I were to write the same thing explicitly with continuations and with-exception-handler, things would get very hairy very quickly. User's are likely to end up implementing this over and over again, because this pattern is common. It is better to have a common exception handling paradigm that supports this behavior from the start. I hope that this at least clarifies some of the rationale for guard. -- Aaron W. Hsu | arcfide@x | http://www.sacrideo.us Programming is just another word for the lost art of thinking.
Description: This is a digitally signed message part
_______________________________________________ Scheme-reports mailing list Scheme-reports@x http://lists.scheme-reports.org/cgi-bin/mailman/listinfo/scheme-reports