[racket] help about a macro that uses a struct define with "make-struct-type"

From: Carl Eastlund (cce at ccs.neu.edu)
Date: Fri Jul 29 12:51:17 EDT 2011

On Fri, Jul 29, 2011 at 12:44 PM, Maurizio Giordano
<maurizio.giorda at gmail.com> wrote:
> On Fri, 2011-07-29 at 12:20 -0400, Carl Eastlund wrote:
>>
>> 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.
> Now it is perfectly clear to me.
> thanks a lot.
>>
>>
>> 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.
> The "templates" I generate at compile-time in the macro are some sort of
> a syntax tree:
>
> An example:
> the macro (three) inputs: < (1 x), 2 > x 3
> will generate an hash like this:
>
> #hash ((mset . #hash((list . #hash((integer . 1)
>                                   (symbol . x)))
>                     (symbol . x)))
>       (symbol . x)
>       (integer . 3))
>
> By using this nested hashtable, the "inject-code" function will
> produce a (recursive) pattern matchers code to be included in the lambda
> code generated by the macro. Symbols in the input are not evaluated,
> they will are considered identifiers to be bound (and unified)
> during the pattern matching.
>
> Therefore, I think I am not using the mset values at compile-time.
> I simply parse the macro inputs to generate a sort of syntax tree
> (i.e. the hashtable).

You are not using them as outputs, but you are using them as inputs.
Even that is problematic, exactly as you have seen.  I suggest writing
a macro using only standard syntax objects containing lists, strings,
symbols, and numbers for both input and output if at all possible.
This will save a lot of trouble.  Using hash tables in syntax objects
can work, but even that brings up some tricky issues.  I find it is
almost always better to consume and produce code that refers to or
produces complex data types, rather than code actually represented as
complex data types.

--Carl



Posted on the users mailing list.