[racket] Help With a Macro (tricky?)

From: Hal Henke (halhenke at gmail.com)
Date: Fri Jan 13 02:20:07 EST 2012

Hi Marjin,

Firstly - wow sorry about all that html :-(

For anyone still interested that first post should have read:

"In other words instead of typing all this:

(class object%
  (init size)                ; initialization argument
  (define current-size size) ; field
  (define/public (get-size)
    current-size)
 .............

I wanted to be able to write something like:

  (init+ size)

that would expand to something like:

  (init size)         ; initialization argument
  (define size+ size) ; field
  (define/public (size++)
    size+)

even better would be an expansion of (init+ size) to:

 (init size++)         ; initialization argument
  (define size+ size++) ; field
  (define/public (size)
    size+)"

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_)"

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:

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

(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_)])))))

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

Thanks again,

Hal

On Wed, Jan 11, 2012 at 9:14 PM, Marijn <hkBst at gentoo.org> wrote:
>
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 11-01-12 04:44, Hal Henke wrote:
> > Hi Racketeers,
>
> Hi Hal,
>

>
> This was a bit difficult to read, but I deduced that you meant
> something like:
>
> (define class1%
>  (class object%
>    (super-new)
>    (init-field size)
>    (define/public (get-size) size) ))
>
> Look it works:
>
> (define class1 (new class1% (size 1)))
> (send class1 get-size)
>
>
> I hope you would then be happy to be able to write:
>
> (define fast-class1% (fast-class size))
>
> (define fast1 (new fast-class1% (size 2)))
> (send fast1 get-size)
>
> To make it work you need something like this macro:
>
> (define-syntax fast-class
>  (lambda (stx)
>    (syntax-case stx ()
>      ((_ _field_)
>       (with-syntax
>           ((getter
>             (datum->syntax
>              #f (string->symbol
>                  (string-append
>                   "get-"
>                   (symbol->string
>                    (syntax->datum #'_field_)))))))
>         #'(class object%
>             (super-new)
>             (init-field _field_)
>             (define/public (getter) _field_)) )))))
>
> Possibly there is some better way to construct the getter identifier.
>
> If you want to stay within syntax-rules, then you have to make the
> getter an argument of your macro like so:
>
> (define-syntax fast-class2
>  (syntax-rules ()
>    ((_ _field_ _getter_)
>     (class object%
>       (super-new)
>       (init-field _field_)
>       (define/public (_getter_) _field_)))))
>
> (define fast-class2% (fast-class2 size get-size))
>
> (define fast2 (new fast-class2% (size 3)))
> (send fast2 get-size)
>
> Hope that helps,
>
> Marijn



Posted on the users mailing list.