* Aaron W. Hsu [2012-03-22 17:09] writes: >> 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.
Agreed. >> 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. Note that I said the "cond-tests". Only the cond-tests are evaluated in the dynamic environment of raise; the <expression>s of the matching cond-clause are evaluated in the dynamic environment of the guard clause. > 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. guard can be expressed as macro that uses with-exception-handler and raise. See SRFI-34 for proof. > 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)))) As (error? c) does not depend on the dynamic environment this would do the same with strategy 2 from above (just more efficiently). > 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. I understand the reason to have a macro for a common use case but I can't see why your example requires full continuations. Helmut _______________________________________________ Scheme-reports mailing list [email protected] http://lists.scheme-reports.org/cgi-bin/mailman/listinfo/scheme-reports
