[racket] Help With a Macro (tricky?)

From: Marijn (hkBst at gentoo.org)
Date: Fri Jan 13 05:37:52 EST 2012

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 13-01-12 08:20, Hal Henke wrote:
> Hi Marjin,
> 
> Firstly - wow sorry about all that html :-(

No problem.

> Secondly thanks very much for your help - your example worked
> great. Only thing is - I'm having trouble generalising the macro to
> handle multiple arguments. The real problem seems to be that
> anytime the term init, init-field, define/public is mentioned
> inside a class, inside a list or any other type of s-expression an
> error gets thrown
> 
> "init-field: use of a class keyword is not in a class top-level
> in: (init-field _field_)"

It's complaining about your using `init-field' outside of `class'.

> so 'm having real difficulty trying to get a macro that spits out
> an arbitrary number of init field define-public pairs e.g.
> 
> (class object% (super-new) (init-field a1) (define/public (get-a1)
> a1) (init-field a2) (define/public (get-a1) a2) etc... )
> 
> So far ive been mucking round with something like this to no
> success:

Your mucking is very familiar and reminds me of my own struggles in
learning syntax-case.

> (define-syntax my-big-class (lambda (stx) (syntax-case stx () ((_
> _field_ ...) #'(class object% (super-new) (my-init _field_) 
> ...)))))

Your mistake is one I have made myself many times: you call my-init as
if it were a function, but macro expansion doesn't work like function
calling. The `class' macro will be the one in charge after my-big-class.

> (define-syntax my-init (lambda [stx] (syntax-case stx () ([_
> _field_] (with-syntax ((getter (datum->syntax #f (string->symbol 
> (string-append "get-" (symbol->string (syntax->datum
> #'_field_))))))) #'[(init-field _field_) (define/public (getter)
> _field_)])))))

Here there is no enclosing `class' thus things like `init-field' are
errors.

> I'm sure theres a simple way around this that I'm missing.

I always find it tricky when to convert from syntax to normal scheme,
when to convert back and the difference between a list of syntax and a
syntax object that contains a list... but in the end I managed to find
the right mix:

(define-syntax fast-class
  (lambda (stx)
    (syntax-case stx ()
      ((_ _field_ ...)
       (with-syntax
           (((_getter_ ...)
             (datum->syntax
              #f
              (map
               (lambda (f)
                 (string->symbol
                  (string-append
                   "get-"
                   (symbol->string f))))
               (syntax->datum #'(_field_ ...)) )) ))
         #'(class object%
             (super-new)
             (init-field _field_ ...)
             (define/public (_getter_) _field_) ...) )))))

(define fast-class1% (fast-class size weight))

(define fast1 (new fast-class1% (size 2) (weight 200)))
(send fast1 get-size)
(send fast1 get-weight)

> Thanks again,

You're welcome,

Marijn
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.18 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEUEARECAAYFAk8QCYAACgkQp/VmCx0OL2wXpQCY8ctNFD8lcEQOwzNP6FFPjxrT
QACdFUXqhHrwEsgW79d0PPIukZHDHyc=
=+9Oa
-----END PGP SIGNATURE-----


Posted on the users mailing list.