[racket] Sometimes (syntax-e #<syntax (lambda (x) #f)>) produces a non-list pair

From: Carl Eastlund (carl.eastlund at gmail.com)
Date: Thu Apr 17 00:22:24 EDT 2014

Syntax objects are a rather complex data type, especially where pairs and
lists are involved.  Essentially, a syntax object containing a list can be
broken up with extra syntax nodes at all, some, or none of its intermediate
conses, depending on how it is constructed.  For example, if you just write
#'(1 2 3), there will be one syntax node at the top level and none anywhere
else.  If you write #'(1 . (2 . (3 . ()))) instead, you get syntax nodes at
each step along the way.  The syntax objects differ, even though '(1 2 3)
and '(1 . (2 . (3 . ()))) produce the same value.

So what happened in your program?  Well, when you define f2 using
proc-with-stx, the define-syntax-rule from proc-with-stx substitutes
(lambda (x) #f) in for expr, and your syntax object is therefore
[essentially] #'(lambda (x) #f).  It's a straightforward list, one syntax
node at the top level.

When you define f using lambda-with-stx, however, the define-syntax-rule
for lambda-with-stx has to substitute (x) for args and #f for body ... in
(lambda args body ...).  I'm guessing the result comes out something like
(lambda . ((x) . (#f . ()))); the process may just automatically put a
syntax node at each cons.  Then proc-with-stx substitutes that for expr,
and you get [essentially] #'(lambda . ((x) . (#f . ()))).

Basically, you can't rely on where syntax-e will split up a list into
syntax objects unless you constructed it yourself.  If you want predictable
results, use syntax->list or syntax->datum.

Carl Eastlund


On Wed, Apr 16, 2014 at 10:33 PM, Alexander D. Knauth
<alexander at knauth.org>wrote:

> Basically, I have a macro, called proc-with-stx, that captures an
> expression and stores it in a syntax object, and I have another macro,
> called lambda-with-stx, that expands to (proc-with-stx (lambda …)).
> When I use (proc-with-stx (lambda (x) #f), then the syntax-e of the
> syntax-object is a list, but when I use (lambda-with-stx (x) #f), which
> should expand to the same thing, the syntax-e of the syntax-object is a
> non-list pair:
>
> #lang racket
>
> (module+ test
>   (require rackunit))
>
> (struct proc+stx (proc stx)
>   #:property prop:procedure (struct-field-index proc))
>
> (define-syntax-rule (proc-with-stx expr)
>   (proc+stx expr #'expr))
>
> (define-syntax-rule (lambda-with-stx args body ...)
>   (proc-with-stx (lambda args body ...)))
>
> (module+ test
>   (define f
>     (lambda-with-stx (x) #f))
>   (define f2                               ; f should expand to f2
>     (proc-with-stx (lambda (x) #f)))
>
>   (define f-stx  (proc+stx-stx f))
>   (define f2-stx (proc+stx-stx f2))
>
>   ;; tests for f:
>   (check-true (procedure? f))
>   (check-equal? (f 1) #f)
>   (check-pred list? (syntax-e f-stx)) ; this test fails, produces
> '(#<syntax lambda> #<syntax (x)> . #<syntax (#f)>) instead
>   ;; same tests for f2
>   (check-true (procedure? f2))
>   (check-equal? (f2 1) #f)
>   (check-pred list? (syntax-e f2-stx)) ; this test passes, produces
> '(#<syntax lambda> #<syntax (x)> #<syntax #f>)
>   )
>
> Why doesn't (syntax-e f-stx) produce a list like (syntax-e f2stx) does?
>
>
>
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20140417/077b2de4/attachment.html>

Posted on the users mailing list.