Context aware macro

32 views
Skip to first unread message

Dimaugh Silvestris

unread,
Aug 30, 2021, 7:50:30 AM8/30/21
to racket...@googlegroups.com
I wanted a 'define' that stores in a hash the arguments and the function definition so I don't keep forgetting argument order and having to go to the file and check. So with my very little knowledge of macros, I wrote this:

#lang racket

(define global (make-hash))

(define-syntax (assign stx)
  (syntax-case stx []
    ([_ (f xs ...) b ...]
     #'[begin
         (hash-set! global 'f (list 'λ '(xs ...) 'b ...))
         (define (f xs ...) b ...)])
    ([_ a b]
     #'[begin
         (hash-set! global 'a b)
         (define a b)])))

Surprisingly it works:
assign.rkt> (assign (sum a b) (+ a b))
assign.rkt> global
'#hash((sum . (λ (a b) (+ a b))))

But what surprises me the most is that it only works at the top level:
assign.rkt>
assign.rkt> (assign foo 3)
assign.rkt> (assign (bar x) (assign foo 7) (* x foo))
assign.rkt> (bar 1)
7
assign.rkt> global
'#hash((bar . (λ (x) (assign foo 7) (* x foo))) (foo . 3))

I suspected I would have had some trouble with local definitions colliding with the global hash, but luckily it isn't happening. Why is that?

Another question: my macro doesn't work with (f . xs) notation. Of course, I could add a [_ f . xs] syntax-case. But I would also have to add a [_ f a ... . xs]. Plus keywords. Is there a way not to have to describe every possible situation?

Sorawee Porncharoenwase

unread,
Aug 30, 2021, 8:17:24 AM8/30/21
to Dimaugh Silvestris, Racket list

But what surprises me the most is that it only works at the top level:
assign.rkt>
assign.rkt> (assign foo 3)
assign.rkt> (assign (bar x) (assign foo 7) (* x foo))
assign.rkt> (bar 1)
7
assign.rkt> global
'#hash((bar . (λ (x) (assign foo 7) (* x foo))) (foo . 3))

Interesting. Following your steps, I got a different result that makes more sense:

'#hash((bar . (λ (x) (assign foo 7) (* x foo))) (foo . 7))

Another question: my macro doesn't work with (f . xs) notation. Of course, I could add a [_ f . xs] syntax-case. But I would also have to add a [_ f a ... . xs]. Plus keywords. Is there a way not to have to describe every possible situation?

For a “flat” function definition, (_ f a ... . xs) is the most general form. It encompasses patterns like (_ f . xs), where a matches 0 times, and (_ f 1 2), where xs is (). So if you have that, you don’t need any other cases.

FYI: function definition allows the curry form too. E.g.,

(define ((f x) y)
  (+ x y))

The most convenient way to parse the header is to switch from syntax-case to syntax-parse, and use the function-header syntax class in syntax/parse/lib/function-header. Lambda doesn’t support currying notation though, so maybe you don’t care about it.


--
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...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/CAN4YmREN1q%2BDTF1UbTHc8LmN3gfnea5HAZCQfc%3DRPyLVHX2yVg%40mail.gmail.com.
Reply all
Reply to author
Forward
0 new messages