Hi Jérôme, `syntax-parse` was in my list to explore!  Thanks for the
example!  I did a new version following your example

(require
 (for-syntax
  racket/base
  racket/syntax
  syntax/parse))

(begin-for-syntax
  (define-syntax-class (element-exp)
    (pattern (element:id value)
             #:with element? (format-id #'element "~a?" #'element)
             #:with var-decl #'(define element value)
             #:with pred-decl #'(define (element? v) (eq? element v)))))

(define-syntax (define-enum stx)
  (syntax-parse stx
    [(_ name (~var e element-exp) ...)
     (with-syntax ([name? (format-id #'name "~a?" #'name)])
       #'(begin
           e.var-decl ...
           e.pred-decl ...
           (define (name? v) (or (e.element? v) ...))))]))

(module+ test
  (require rackunit)
  (define-enum animal (dog 1) (cat "2"))
  (check-true (dog? dog))
  (check-false (cat? dog))
  (check-true (animal? dog))
  (check-false (animal? 3)))

I removed the prefix and added a function to check if a value is a
valid enum value.  When trying to write the later, I stuck on the
expression

(define (name? v) (or e.element ...))

which I knew was not what I wanted.  Then I though  "You know, I
really liked to write (or (e.element v) ...).  You know what .. why
not give a try?".  I did and it worked as a charm!  I am amused by the
power of `...` in templates.

On Mon, Apr 29, 2019 at 12:37 AM Jérôme Martin
<jerome.martin....@gmail.com> wrote:
>
> Hello there!
>
> I'm really glad you're picking up Racket and enjoying it!
>
> I've been through the same paths and struggles before, so thank you very much 
> for posting that piece of
> experience here :)
>
> For your information, here is a syntax-parse version of your macro, which I 
> find simpler to write and understand:
> (it's basically syntactic sugar over syntax-case, but it's really useful!)
>
>     #lang racket/base
>
>     (provide
>       define-enum)
>
>     (require
>       (for-syntax
>         racket/base
>         racket/syntax
>         syntax/parse))
>
>     (define-syntax (define-enum stx)
>       (syntax-parse stx
>         [(_ name (element value) ...)
>          #:with (name-element? ...)
>                 (datum->syntax
>                   #'(element ...)
>                   (map (lambda (elem)
>                          (format-id elem "~a-~a?" #'name elem))
>                        (syntax->list #'(element ...))))
>          #'(begin
>              (define element value) ...
>              (define (name-element? v)
>                (eq? element v)) ...)]))
>
>     (module+ test
>       (require rackunit)
>
>       (define-enum unit
>         (dry #\d)
>         (empty #\.)
>         (rock #\#)
>         (water #\~))
>
>       (check-true (unit-dry? #\d))
>       (check-false (unit-empty? #\#))
>       (check-false (unit-rock? #\~))
>       (check-true (unit-water? #\~)))
>
> To remove that ugly map, which requires transforming syntaxes to list then 
> back to syntaxes, you can use a syntax-class:
>
>     (begin-for-syntax
>       (define-syntax-class (element-exp unit)
>         (pattern (element value)
>           #:with pred-name (format-id #'element "~a-~a?" unit #'element)
>           #:with variable #'(define element value)
>           #:with predicate #'(define (pred-name v) (eq? element v)))))
>
>     (define-syntax (define-enum stx)
>       (syntax-parse stx
>         [(_ name (~var e (element-exp #'name)) ...)
>          #'(begin
>              e.variable ...
>              e.predicate ...)]))
>
> It's a bit more complicated at first, but it becomes really powerful once you 
> understand how syntax-parse and syntax-classes work.
>
> (the tricky part here is that I'm using a syntax-class that takes the unit 
> name as an argument, which is not so common)
>
> Have fun ;)
>
>
> --
> You received this message because you are subscribed to the Google Groups 
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to racket-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.



-- 
Abraço,
Wanderley Guimarães

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to