[racket-dev] struct + match not interacting via a macro

From: Jay McCarthy (jay.mccarthy at gmail.com)
Date: Mon Oct 10 08:38:10 EDT 2011

One of the bindings that

          (define-struct foo (a b) #:transparent #:mutable)

binds is 'foo', and it is bound the static information about the
structure, basically:

(define-syntax foo (list #'make-foo #'foo? (list #'foo-a #'foo-b)
(list #'set-foo-a! #'set-foo-b!)))

(But not exactly right because there's some other information. See
around 'struct-info' in the docs.)

When you write

(match ...
 [(struct foo (... ...))
  ...])

the static binding for 'foo' is inspected (using syntax-local-value)
to get that static information so it knows to use foo? and foo-a and
foo-b for the pieces.

In the case of your macro,

(begin
    (define-values (foo struct:foo make-foo foo? foo-a set-foo-a!
foo-b set-foo-b!)
      (let ()
        (begin
          (define-struct foo (a b) #:transparent #:mutable)
          (let ([make-foo
                 (lambda (a b) ...)]
                [set-foo-a! (lambda (struct-inst new-val) ...)]
                [set-foo-b! (lambda (struct-inst new-val) ...)])
            (values foo struct:foo make-foo foo? foo-a set-foo-a!
foo-b set-foo-b!))))))

You are binding foo, but you are only binding it as a *value* rather
than as *syntax*. So when match see the (struct foo ...) clause, it
sees that foo has no static binding and thus says that no such struct
exists.

You would have to expand to something that includes both the static
and runtime pieces:

(begin (define-values ( ... ) ... )
          (define-syntaxes ( ... ) ... ))

But that's going to be difficult because ideally you'd just use the
static binding that define-struct sets up. One approach would be to
put the define-struct at the top-level but with altered names that you
control:

(begin (define-struct foo* (a b) ...)
          (define-syntax foo foo*)
          (define (make-foo ...) (make-foo* ... ))
          etc)

So that you could still add whatever you're adding. The define-type
macro in PLAI does this (although it doesn't make the structs
compatible with match.)

Jay

On Mon, Oct 10, 2011 at 6:24 AM, Shriram Krishnamurthi <sk at cs.brown.edu> wrote:
> On Mon, Oct 10, 2011 at 8:13 AM, Jay McCarthy <jay.mccarthy at gmail.com> wrote:
>> And if it isn't clear, since it is looking at foo's static binding,
>> your macro is only binding the values from define-struct, not the
>> syntaxes.
>
> Jay, can you elaborate?  What is doing the looking -- the match struct
> clause?  What does it mean to "look at foo's static binding"?
>
> I understand that my macro is binding only the values, not the
> original syntaxes (other than "foo" itself, which is carried through
> from the user's source).  The name "struct:foo" here is completely
> synthetic because it's being introduced by build-struct-names.  Is
> that what you're referring to?
>
> In that case, does writing such a macro require an explicit breaking
> of hygiene?
>
> Shriram
>



-- 
Jay McCarthy <jay at cs.byu.edu>
Assistant Professor / Brigham Young University
http://faculty.cs.byu.edu/~jay

"The glory of God is Intelligence" - D&C 93



Posted on the dev mailing list.