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

From: Maurizio Giordano (maurizio.giorda at gmail.com)
Date: Fri Jul 29 12:05:17 EDT 2011

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.
  
> 
> 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.
> 
> Carl Eastlund
> 
> On Fri, Jul 29, 2011 at 8:35 AM, Maurizio Giordano
> <maurizio.giorda at gmail.com> wrote:
> > REPOSTED DUE TO COPY/PASTE ERRORS IN MY ORIGINAL MAIL.
> > ------------------------------------------------------
> >
> > Hi all,
> >
> > I am not a racket expert, so my problem could be
> > simply due to my few knwoledge about macros.
> >
> > My problem is when I am using macros and
> > user-defined structs.
> >
> > I have defined my new structure with "make-struct-type":
> >
> > ; Multiset datatype definition
> > (define-values (s:mset make-mset mset? mset-ref mset-set!)
> >   (make-struct-type 'mset #f 1 0 #f
> >              (list (cons prop:custom-write mset-print))))
> >
> > I have defined a new reader and writer for this new datatype.
> > Here you find an example of use of the "mset" datatype.
> >
> >> (define d1 (make-mset #(1 2 3 4)))
> >> d1
> > <1,2,3,4>      ; printed (and read) as a comma-separated set of elements
> > encolsed by <>
> >> (mset? d1)   ; the datatype checker
> > #t
> >
> > Now I have the following macro:
> >
> >  (require (for syntax multiset))   ;; import mset? for macro
> >
> >  (define-syntax (mm stx)
> >   (syntax-case stx ()
> >        [(_ input ...)
> >         (let* ((l1 (syntax '(input ...)))
> >                (l2 '(input ...)))
> >           (map (lambda (x) (print-type x)) l2)   ; assume print-type is
> > imported for syntax
> >           (datum->syntax stx `(map (lambda (x) (print-type x)) ,l1)
> > stx))]))   ; I need this quasiquote/unquote
> >
> > Where "print-type" is a trivial function that checks the type of "x"
> > and prints it:
> >
> >  (define (print-type x)
> >   (cond ((symbol? x) (printf "SYM: ~s\n" x))
> >          ((integer? x) (printf "INT: ~s\n" x))
> >          ((list? x) (printf "LIST: ~s\n" x))
> >          ((mset? x) (printf "MSET: ~s\n" x))
> >         (else (printf "UNK: ~s\n" x)))
> >   x)
> >
> > I get the following printout when I call the macro like this:
> >
> >> (mm 1 x (1 y) < 1, z >)
> > INT: 1
> > SYM: x
> > LIST: (1 y)
> > UNK: <1, z>
> > ...
> > INT: 1
> > SYM: x
> > LIST: (1 y)
> > MSET: <1, z>
> >
> > It seems that when binding "l2" in the let, the "mset" datatype
> > information
> > is lost, while "l1" in the macro template contains all information.
> >
> > >From the documentation of "syntax->datum" I have read the following:
> > "Returns a datum by stripping the lexical information, source-location
> > information, properties, and certificates from stx. Inside of pairs,
> > (immutable) vectors, (immutable) boxes, immutable hash table values (not
> > keys), and immutable prefab structures, syntax objects are recursively
> > stripped."
> >
> > My structure is not a prefab ... Is this the problem?
> > How can I preserve the "mset" information in the let binding?
> >
> > I will appreciate any help.
> >
> > Thank You.
> >
> > Maurizio.
> >
> > PS. I read Tom McNulty last post "Advice on a macro for mutating
> > structs...". Maybe my problem has some similarities with his...
> >
> >
> > _________________________________________________
> >  For list-related administrative tasks:
> >  http://lists.racket-lang.org/listinfo/users
> >
> >




Posted on the users mailing list.