JavaScript's with statement allows one to modify object members. This may not be possible for certain types of values (such as strings) using the let-with macro as defined above.
One could generalize let-with to bind values from several association lists. It could have the form:
(let-with
((alist0 (key00 key01 key02...))
(alist1 (key10 key11 key12...)))
expr0
expr1
...)
Aside from being more general, the above form closely resembles the let form. I prefer this over the simpler form, though I would understand if your taste and needs differ.
Here's my implementation of the general form--it uses two auxiliary macros, one to generate two lists (alists and their corresponding keys) and the other to emit the actual code (which looks almost exactly like your definition above):
(define-syntax let-with
(syntax-rules ()
((let-with bindings . body)
(gen-let-with bindings () () body))))
(define-syntax gen-let-with
(syntax-rules ()
((gen-let-with () alists keys body)
(emit-let-with-code alists keys body))
((gen-let-with ((alist (key)) . rest-bindings) alists keys body)
(gen-let-with
rest-bindings
(alist . alists)
(key . keys)
body))
((gen-let-with ((alist (key . rest-keys)) . rest-bindings) alists keys body)
(gen-let-with
((alist rest-keys) . rest-bindings)
(alist . alists)
(key . keys)
body))))
(define-syntax emit-let-with-code
(syntax-rules ()
((emit-let-with-code (alist ...) (key ...) (expr ...))
(let ((key (cond ((assq 'key alist) => cdr))) ...) expr ...))))
Perhaps there is a simpler definition. I haven't played with macros in a while. =)
Here are some examples:
(define alist '((first . "Jane") (middle . "Q") (last . "Doe")))
(define blist '((first . "John") (middle . "R") (last . "Lee")))
(define clist '((first . "Jose") (middle . "S") (last . "Paz")))
(define first '((title . "Ms") (suffix . "Esq")))
(let-with
()
"Hello, world!") ; => "Hello, world!"
(let-with
((alist (first middle last)))
(string-append first " " middle ". " last)) ; => "Jane Q. Doe"
(let-with
((alist (first))
(blist (middle last)))
(string-append first " " middle ". " last)) ; => "Jane R. Lee"
(let-with
((alist (first))
(blist (middle))
(clist (last)))
(string-append first " " middle ". " last)) ; => "Jane R. Paz"
(let-with
((first (title))
(alist (first))
(blist (middle))
(clist (last))
(first (suffix)))
(string-append first " " middle ". " last)) ; => "Jane R. Paz"
(let-with
((alist (first middle last)))
(set! first "Rose")
(string-append first " " middle ". " last)) ; => "Rose Q. Doe"
(let-with
((alist (first middle last)))
(string-append first " " middle ". " last)) ; => "Jane Q. Doe"
Since let-with expands into a single let, the third-to-last example works.
The last two examples demonstrate the inability to modify a value in its corresponding association list.