5
\$\begingroup\$

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.

asked Mar 23, 2011 at 4:12
\$\endgroup\$
0

1 Answer 1

3
\$\begingroup\$

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.

answered Apr 19, 2011 at 7:06
\$\endgroup\$
1
  • \$\begingroup\$ 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. :-( \$\endgroup\$ Commented Apr 27, 2011 at 12:27

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.