On Dec 9, 2014, at 7:40 AM, Gustavo Massaccesi <[email protected]> wrote:
> I think that you want to capture the variables. I made a simplified > example. The other variables (for example "hidden") are not capture, > as usual. > > ;--- boilerplate.rkt --- > #lang racket > (define (call-with-?? proc) (proc)); just for the example > (define exn:fail:network? exn:fail?); just for the example > (provide with-db) > (define-syntax with-db > (lambda (stx) > (syntax-case stx () > [(_ body ...) > (with-syntax ([err-msg (datum->syntax stx 'err-msg stx stx)] > [db (datum->syntax stx 'db stx stx)]) > ; --- start boilerplate > (syntax-protect > (syntax/loc stx > (let/ec fail-network > (with-handlers [(exn:fail:network? (lambda (e) > (set! err-msg > "database connection error") > (fail-network)))] > (define db 5) > (define hidden 7) > (call-with-?? (lambda () body ...)))))) > ; --- end boilerplate > )]))) > > ;--- main.rkt > #lang racket > (require "boilerplate.rkt") > (define err-msg #f) > (define hidden "BU") > (with-db > (displayln db); ==> 5 > (displayln hidden); ==> "BU" > (/ 1 0) > (display "never")) > (when err-msg > (error 'error err-msg)) > > ;------- > > There is a big red warning in the Racket documentation about macros > with variable capture, but I can't find it. It recommends to use > syntax-parameters, but the syntax parameter can't change the value of > err-msg after the macro body had finished. But this works: #lang racket (require racket/stxparam) (define-syntax-parameter thing #f) (define x #f) (syntax-parameterize ([thing (make-rename-transformer #'x)]) (set! thing 5)) x ; 5 > The problem is that if you > use the with-db macro inside a with-super-db macro, the results are > strange. > > Gustavo > > > On Mon, Dec 8, 2014 at 8:45 PM, George Neuner <[email protected]> wrote: >> Hi all, >> >> This is more curiosity than a problem. >> >> I am writing a web service which uses a database and there is a fair bit of >> boilerplate exception handling code which is needed in just about every >> servlet. It takes up a lot of page and indentation space in the source and >> just offends my sensibilities. I have created a macro to condense the >> visual, but I'm not entirely happy with it because of how it deals with >> interactions among the template, the body and the surrounding code. >> >> As used inline, everything I am doing fits into the following pattern: >> >> (let [ >> (err-msg #f) >> ] >> >> : >> >> ; --- start boilerplate >> (let/ec fail-network >> (with-handlers [ >> (exn:fail:network? >> (lambda (e) >> (set! err-msg "database connection error") >> (fail-network))) >> ] >> (let [ >> (db (connect-database)) >> ] >> >> (let/ec fail-sql >> (with-handlers [ >> (exn:fail:sql? >> (lambda (e) >> (let [(info (exn:fail:sql-info e))] >> (set! err-msg (cdr (assoc 'message info))) >> (fail-sql)))) >> ] >> >> (call-with-transaction db >> (lambda () >> : >> < body ... > >> : >> ) >> #:isolation 'repeatable-read) >> >> ) >> >> (disconnect db)) >> >> ))) >> ; --- end boilerplate >> >> >> ; err-msg needed here >> >> ) >> >> >> The problems, of course, are that "err-msg" is external to the boilerplate >> code, and "db" is internal to it. The exception handlers in the >> boilerplate need access to "err-msg" (or whatever the actual variable name >> might be) and code in the <body> needs to reference "db" which is only >> defined within the scope of the macro. >> >> I've gotten it to work with syntax-rules by passing the problem names in as >> arguments: >> >> (define-syntax with-database >> (syntax-rules () >> ((with-database-connection db err-msg body ...) >> ... ))) >> >> knowing that I can use any names externally or in the body (the above is >> just example). >> >> This works, but having to pass in the (name of the) required error status >> variable is ugly. I know I can add a keyword (or several) to handle the >> status variable, but reasonable syntaxes for it are convoluted. Something >> like "with-database-connection <JOE> sending errors to <BOB> ..." >> obviously is possible, but is unwieldy (and un-Scheme-like [ un-Schemely? ] >> ) - it looks more like Smalltalk or Lisp's loop language than it does like >> Scheme. 8-) >> >> I suppose I could require to pass in exception handler functions rather than >> a target for their output, but that also is unwieldy and error prone because >> the functions have to be inserted at different nesting levels. >> >> Is there some idiomatic way people normally handle this kind of broken >> abstraction? I've searched a bit trying to find a discussion of something >> like this, but so far haven't found anything enlightening. >> >> Thanks, >> George >> >> >> ____________________ >> Racket Users list: >> http://lists.racket-lang.org/users > ____________________ > Racket Users list: > http://lists.racket-lang.org/users ____________________ Racket Users list: http://lists.racket-lang.org/users

