Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I've implemented a let-with macro that takes an association list, keyed by symbols, that enables code to bind their corresponding values to local variables.

It's designed to have a similar effect to JavaScript's with, but without with's attendant problems (by making you explicitly list the variables to bind).

(define-syntax let-with
  (syntax-rules ()
    ((let-with alist (key ...) expr ...)
     (let ((key (cond ((assq 'key alist) => cdr))) ...) expr ...))))

I'd love to hear of any improvements to let-with's interface and/or implementation.

Example usage:

(define alist '((first . "Jane")
                (last . "Doe")))
(let-with alist (first last)
  (string-append first " " last))    ; "Jane Doe"

Keys that don't exist in the incoming alist receive an undefined value; they do not fail to get bound, unlike JavaScript's with.

share|improve this question
add comment

1 Answer 1

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.

share|improve this answer
    
Thanks for your answer---I haven't forgotten about you (I've read it the moment it was posted). I wanted to write a full response to that, with my ideas about how such an extended macro might be implemented, etc., but my free time is so very limited at the moment. :-( –  Chris Jester-Young Apr 27 '11 at 12:27
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.