4
votes

I'm currently working on an assigment about racket macros. In one of the questions we`re asked to define a macro my-set! which acts like this:

(define x 3)
(define y 5)
(define z 7)
(my-set! (x (+ x y)))
(my-set! (x (+ x y)) (z 6))
x
13
y
5
z
6

I found this interesting document on syntax-case http://www.cs.indiana.edu/~dyb/pubs/tr356.pdf

Currently my macro works but i'm trying to add a "fender" like on page 10 of the document to fend off errors like if one of the variables arent identifiers or anything else.

Here`s my code:

(define-syntax my-set!
  (letrec ((all-ids?
            (λ (ls)
              (or (null? ls)
                  (and (identifier? (car ls))
                       (all-ids? (cdr ls)))))))
    (lambda (x)
      (syntax-case x ()
        ((_ (var val) (var2 val2) (var3 val3) ...)
         (all-ids? (syntax (var var2 var3 ...)))
         (syntax (begin (set! var val) (my-set! (var2 val2) (var3 val3) ...))))
        ((_ (var val))
         (syntax (set! var val)))))))

If I test this exact code without the fender, it works perfectly. But when I run this:

(define a 1)
(define b 1)
(define c 1)

(my-set! (a 3) (b 4) (c 5))

I get this:

car: contract violation expected: pair?
given: syntax:C:\Users\mgiroux\Desktop\define-myset.rkt:40:26 (a b c)

Seems like all-ids? cant (car) of (a b c) cause its not a list? I tried passing it as a list but didnt work either, i seem to have copied exactly the way they do it in the pdf I linked.. What am I missing here?

1

1 Answers

3
votes

#'(var var2 var3 ...) is indeed not a list. It's a syntax object that wraps a list. You should use syntax->list to extract out the items into a list, thus your guard should look like:

(all-ids? (syntax->list #'(var var2 var3 ...)))