[racket] Problem with macro

From: Danny Yoo (dyoo at hashcollision.org)
Date: Sun Sep 2 00:23:25 EDT 2012

> So I tried modifying the macro to the following.
>
> ;(let/set-prompt args prompt (body ...))
> (define-syntax let/set-prompt
>   (syntax-rules ()
>     [(_                ARGS (BODY ...)) (call-with-continuation-prompt
> (let ARGS (λ () BODY ...)))]
>     [(_ PROMPT         ARGS (BODY ...)) (call-with-continuation-prompt
> (let ARGS (λ () BODY ...)) PROMPT)]
>     [(_ PROMPT HANDLER ARGS (BODY ...)) (call-with-continuation-prompt
> (let ARGS (λ () BODY ...)) PROMPT HANDLER)]))


The patterns of your new macro have a different shape than your
original macro, so it's very possible that the new use of the macro is
not following the same pattern matching control paths as the first.


But since you're only using one particular case in your examples,
let's simplify.  Rather than make it overly general with three
syntactic cases, I'd recommend reducing it down to just a single case
for now, to help debug the situation.


Try this definition for let/set-prompt for the moment:

;;;;;;;;;;;;
(define-syntax let/set-prompt
  (syntax-rules ()
    [(_ PROMPT ARGS BODY ...)
     (call-with-continuation-prompt
      (let ARGS (λ () BODY ...)) PROMPT)]))
;;;;;;;;;;;;


Note that this version is fine: you'll get the values you wanted before!


Then, change it to a version that exhibits the erroneous values you're seeing:

;;;;;;;;;;;;
(define-syntax let/set-prompt
  (syntax-rules ()
    [(_ PROMPT ARGS (BODY ...))
     (call-with-continuation-prompt
      (let ARGS (λ () BODY ...)) PROMPT)]))
;;;;;;;;;;;;


Why does this cause a problem?  Note that in the erroneous case, the
third part, the part with the (BODY ...), ends up losing its outer
parens, so the expanded version of a body such as:


(let/set-prompt prompt-3 ()
                (+ 1000
                   (abort-to-prompt p 0)
                   2000))

ends up reducing the body so that +, 100, (abort-to-prompt p 0), and
2000 end up being the components in the LET, rather than the
application of + to the rest.  That is, the reduction looks like this:

(let/set-prompt prompt-3 ()
                (+ 1000
                   (abort-to-prompt p 0)
                   2000))

==>

(call-with-continuation-prompt
 (let () (λ ()
           +
           1000
           (abort-to-prompt p 0)
           2000))
 prompt-3)



And whoops!  That's where we're getting the funky values back: the use
of + just got ripped apart by the macro, by accident.  We popped its
bubble, and the components just spilled out into the body of the let.


Hope this helps!


Posted on the users mailing list.