[racket] help about a macro that uses a struct define with "make-struct-type"
On Fri, Jul 29, 2011 at 12:05 PM, Maurizio Giordano
<maurizio.giorda at gmail.com> wrote:
> Hi Carl,
>
> On Fri, 2011-07-29 at 11:09 -0400, Carl Eastlund wrote:
>> Maurizio,
>>
>> The problem here may be that macros are expanded at a separate phase
>> from the program's run-time. Different phases have different stores,
>> and thus different versions of structure definitions. Your custom
>> reader for the mset datatype produces an mset for use at run-time.
>> The run-time print-type detects this kind of mset, but the
>> compile-time print-type expects a different version of an mset.
> Ok. the difference between the two phases is now clear to me...
> what is not still clear is:
> 1) at compile-time the "mset?" checker function is known... otherwise I
> would see an "undefined mset?"
> (in fact I specify a (require (for-syntax multiset)), where multiset is
> a module implementing the new datastructure).
> 2) always at compile-time, the (mset? < ... >) expression returns #f.
> So it seems to me that at compile-time the struct object has lost some
> information.
There is one module called "multiset", but all of its definitions are
executed twice because your program uses them in two different phases:
once at run-time and once at compile-time. That means
there are two different mset types with two different constructors and
two different mset? predicates. Call the run-time versions mset.1 and
mset?.1, and the compile-time versions mset.2 and mset?.2. Similarly,
you have print-type.1 and print-type.2 at run-time and compile-time.
Your custom reader produces an mset.1 value. Your macro calls
print-type.2 which checks mset?.2, and mset?.2 produces #false when
given an mset.1 value. The code your macro produces, however, calls
print-type.1, which checks mset?.1, and that produces #true (I'm using
the new long-form names of #f and #t for readability). So no
information is being lost -- it's just that there are two versions of
everything running around, and they cannot be mixed and matched.
>> Prefab structures would fix this part of the issue, because they do
>> not generate new types, they merely describe a subset of existing
>> types. However, you cannot add a custom reader or writer property to
>> prefab types, so another part of your interface will break.
> Yes, you are right... I would like to keep my custom reader/writer.
> So I cannot use prefab structs.
>>
>> I do not know precisely what you need to detect this type at
>> compile-time for, so I don't have any advice on how to handle this for
>> your purposes. I hope I have at least clarified the behavior you see.
>
> At compile-time I would like to process the macro inputs (of course also
> <...> structs) to generate some pattern-matching "templates" to be
> injected in the code the macro generates and execute at runtime.
> Something like this:
>
> (define-syntax (mm stx)
> (syntax-case stx ()
> [(_ input ...)
> (let* ((l1 (syntax '(input ...)))
> (templates (... process/and/recognize msets in l1 ...)))
> (datum->syntax stx
> `(lambda (x) ,(inject-code patterns)) stx))]))
>
> Therefore, what I really need is that the new data structure is parsed
> (and its type cecked) at compile time.
>
> Thanks,
> Cheers,
> Maurizio.
Are you sure you want to put mset values in as literal syntax? That
leads to all sorts of odd behavior -- for instance, the contents of
those msets will need to be syntax at compile-time if they are to
contain expressions, but non-syntax at run-time if they are to contain
useful values. The expansion system will not do this plumbing for
you. You'll get a lot more "bang for your buck" if you instead just
use a match expander as both a pattern to recognize msets and a
constructor to build them. This avoids all issues of crossing phase
boundaries, because the compile-time code acts entirely by recognizing
identifier bindings, and does not have to know about the
representation of msets at all.
--Carl