[racket] for/hash: bad syntax in: for/hash

From: Eli Barzilay (eli at barzilay.org)
Date: Tue Jan 3 14:15:10 EST 2012

Two hours ago, Marijn wrote:
> Hi,
> for/hash is giving me a syntax-error, but the error is in
> macro-expanded code which is not shown by default and which is also
> seemingly inaccessible via the macro-stepper. The for/hash
> expression works outside my macro, so I guess it's my fault, but it
> would help if the syntax-error could be a bit more informative. The
> code: [...]

1. The problem is not `for/hash' -- it's in your macro.  You can see
   that by replacing it, for example, with `let*' and the error
   changes accordingly.

2. Minimizing the code in obvious ways got me down to this macro soup
   which fails in the same way:

     (define-syntax dependent-boxes
       (syntax-rules ()
         ((_ ((_variable_ . _rule_) ...))
          (let ()
            (define-syntax with-variables
              (syntax-rules (_variable_ ...)
                [(_ (a (... ...))) ((with-variables a) (... ...))]
                [(_ _variable_) (list '_variable_)]
                [(_ non-variable) non-variable]))
            (define-syntax rule-with-variables
              (syntax-rules ()
                [(_ (rule)) (lambda () (with-variables rule))]))
            (list (rule-with-variables _rule_) ...)))))
     (dependent-boxes ((profit (let* ((y 1)) 2))))

   Looks like the macro stepper does not step through local macros (at
   least not in this case), but it did the first step of expanding the
   `dependent-boxes' macro.

3. This leads to a smaller code that fails the same.

     (let ()
       (define-syntax with-variables
         (syntax-rules (profit)
           ((_ (a ...)) ((with-variables a) ...))
           ((_ profit) (list 'profit))
           ((_ non-variable) non-variable)))
       (define-syntax rule-with-variables
         (syntax-rules () ((_ (rule)) (lambda () (with-variables rule)))))
       (list (rule-with-variables ((let* ((y 1)) 2)))))

4. It's now easy to continue reducing it to the core of the problem:

     (define-syntax with-variables
       (syntax-rules ()
         ((_ (a ...)) ((with-variables a) ...))
         ((_ a) a)))
     (with-variables (let* ((y 1)) 2))

   Looks like you're doing a code walk (which is what makes me think
   that this is too complex for whatever it is you're trying to do),
   and treat some names in a special way.  The problem is that

     ((with-variables a) ...)

   is creating a function application so the error is the same as just
   entering `let*' to get its value -- and the only error that it can
   throw at this point is a "bad syntax" with the whole expression,
   which is just `let*'.

5. And BTW, the reason it doesn't work is that the first expansion
   gets to

     ((with-variables let*) (with-variables ((y 1))) (with-variables 2))

   and this form is not a macro -- so it's expanded as a function

     (#%app ...same...)

   and the rest is obvious.

          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!

Posted on the users mailing list.