Re: [racket-users] Macro-generating macros

2015-09-04 Thread Alexander D. Knauth

> On Sep 4, 2015, at 4:26 AM, Konrad Hinsen  wrote:
> 
> Brian Mastenbrook writes:
> 
>> It's a capture problem. In the first case, you're just binding the
>> name "send" locally and all is well. In the second case, you're
>> trying to introduce a binding for "send" that you didn't get from
>> the input form.
> 
> Ahhh that one has bitten me before, but I had forgotten about it.
> Thanks for the reminder!
> 
>> You're also getting a confusing error because "send" is already
>> bound; try using a name that's not already defined and you should
>> get an unbound identifier.
> 
> I used a bound symbol intentionally to see if I can shadow an existing
> syntax transformer binding.

Ok, if you *really* want to shadow an existing binding, you can use 
datum->syntax, but using a syntax parameter is much better:
(define-syntax (def stx)
  (syntax-parse stx
[(_ (fn-name:id arg:id ...) body ... )
 #:with send-id (datum->syntax #'fn-name 'send)
 #'(define (fn-name arg ...)
 (let-syntax ([send-id (λ (stx)
 (syntax-parse stx
   [(send-id obj:expr method:id x:expr (... 
...))
#'(method obj x (... ...))]))])
   body ...))]))

>> Alternatively, you can use a syntax parameter, which is probably
>> the ideal solution here.
> 
> At least it's one that works. It feels like cheating to use dynamic
> scoping to get around a problem with lexical scoping, but knowing when
> to cheat is a fundamental competence when dealing with any bureaucracy ;-)

Um, the reason a syntax parameter is better is that it *does* follow the 
lexical scoping rules, where the unhygienic version does weird things you 
wouldn't expect. Using datum->syntax is cheating a lot more, and syntax 
parameters deal with problems like this in a much better way.

P.S.
Have you read Fear of Macros? If you haven't, I highly recommend it because 
it's awesome.

> Thanks again,
>  Konrad.

-- 
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.


Re: [racket-users] Macro-generating macros

2015-09-04 Thread William Cushing
Racket's syntax-expander deliberately goes out of its way to break exactly
this example.  ("hygiene")

The issue/bug/ambiguity it is protecting you from is:
  (let ((send (lambda args (length args)) ))
(def (foo3 x y)
   (send x + y)
 ))
  (foo3 2 3) ;; In lisps with poor grooming, 5.  In racket, 3.  3 is not
what you wanted this time, but it is the better default behavior overall.


There are many ways to get exactly the desired syntactic behavior; syntax
parameters work, as does datum->syntax.


If you're willing to bend a little, a more racket-y solution, it seems to
me, is to force the user of the syntax to give you a name, like:
  (define-syntax-rule (with-SVO-as name body ...) (let-syntax ((name
(syntax-rules [(_ s v o ...) (v s o ...)] ))) body ...)

Which can be used like:
  (define (foo4 x y) (with-SVO-as send (send x + y)))

Or like:
  (define-syntax send (with-SVO-as n n))
  (define (foo5 x y) (send x + y))

Or like:
  (define (foo6 x y) (define-syntax send (with-SVO-as n n)) (send x + y))


That approach doesn't work so well for things like:
  (with-slots  (x y z) (person-x person-y person-z) the-person
(sqrt (* x x) (* y y) (* z z)))

That is, when there are lots of names to be bound, and they're pretty much
always the same, then the repetition/renaming at each use-site gets quite
tiresome; that is the problem that modules solve.

-Will


On Thu, Sep 3, 2015 at 9:59 AM, Brian Mastenbrook 
wrote:

> On Sep 3, 2015, at 11:44, Konrad Hinsen 
> wrote:
>
> > Hi everyone,
> >
> > Here's another plea for help from the macro experts. I am trying to
> > write a macro whose expansion contains another macro, more precisely a
> > let-syntax form. My full example is attached below. In the first part,
> > I use a let-syntax directly. In the second part, I use a macro that
> > generates exactly the form that I wrote by hand in the first part -
> > but then the let-syntax seems to be ignored.
> >
> > The macro stepper isn't of much help here. It shows the expansion
> > of (defn (foo2 ...)) into essentially what I wrote by hand for foo1,
> > and then declares the expansion finished.
> >
> > Can anyone tell me (1) why this doesn't work and (2) how to fix it?
>
> It's a capture problem. In the first case, you're just binding the name
> "send" locally and all is well. In the second case, you're trying to
> introduce a binding for "send" that you didn't get from the input form.
> You're also getting a confusing error because "send" is already bound; try
> using a name that's not already defined and you should get an unbound
> identifier.
>
> You can fix this in one of two ways. Your `def' macro could take the name
> of the `send' macro it binds as a parameter, which gets a little ugly.
> Alternatively, you can use a syntax parameter, which is probably the ideal
> solution here.
>
> (require (for-syntax syntax/parse))
> (require racket/stxparam)
>
> (define-syntax-parameter send (lambda (stx) (raise-syntax-error 'send
> "send used out of context")))
>
> (define-syntax (def stx)
>  (syntax-parse stx
>[(_ (fn-name:id arg:id ...) body ... )
> #'(define (fn-name arg ...)
> (syntax-parameterize ([send (λ (stx)
>   (syntax-parse stx
> [(send obj:expr method:id x:expr
> (... ...))
>  #'(method obj x (... ...))]))])
>  body ...))]))
>
> (def (foo2 x y)
>  (send x + y))
>
> (foo2 2 3)
>
>
> --
> Brian Mastenbrook
> br...@mastenbrook.net
> http://brian.mastenbrook.net/
>
> --
> 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.
>

-- 
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.


Re: [racket-users] Macro-generating macros

2015-09-04 Thread Konrad Hinsen
Alexander D. Knauth writes:

 > > At least it's one that works. It feels like cheating to use dynamic
 > > scoping to get around a problem with lexical scoping, but knowing when
 > > to cheat is a fundamental competence when dealing with any bureaucracy ;-)
 > 
 > Um, the reason a syntax parameter is better is that it *does*
 > follow the lexical scoping rules, where the unhygienic version does
 > weird things you wouldn't expect. Using datum->syntax is cheating a
 > lot more, and syntax parameters deal with problems like this in a
 > much better way.

I agree that datum->syntax is cheating a lot more, no question.

Still, I just used it, and I don't feel bad about it because it makes
my code a lot more readable. I had gotten to the point of having a
macro introduce generated identifiers as syntax parameters for use by
another macro generated by the first macro as well.

Actually, I felt exactly like when I have to fight a type system: I
know my solution is OK, but the compiler cannot prove it and therefore
rejects it. In those cases I feel entitled to cheat as much as
necessary.

 > P.S.  Have you read Fear of Macros? If you haven't, I highly
 > recommend it because it's awesome.

It is. I had read it a year ago, and now re-read it. I'll probably have
to read it again in the future, but it *is* awesome :-)

Konrad.

-- 
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.


Re: [racket-users] Macro-generating macros

2015-09-04 Thread Konrad Hinsen
Brian Mastenbrook writes:

 > It's a capture problem. In the first case, you're just binding the
 > name "send" locally and all is well. In the second case, you're
 > trying to introduce a binding for "send" that you didn't get from
 > the input form.

Ahhh that one has bitten me before, but I had forgotten about it.
Thanks for the reminder!

 > You're also getting a confusing error because "send" is already
 > bound; try using a name that's not already defined and you should
 > get an unbound identifier.

I used a bound symbol intentionally to see if I can shadow an existing
syntax transformer binding.

 > Alternatively, you can use a syntax parameter, which is probably
 > the ideal solution here.

At least it's one that works. It feels like cheating to use dynamic
scoping to get around a problem with lexical scoping, but knowing when
to cheat is a fundamental competence when dealing with any bureaucracy ;-)

Thanks again,
  Konrad.

-- 
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.


[racket-users] Macro-generating macros

2015-09-03 Thread Konrad Hinsen
Hi everyone,

Here's another plea for help from the macro experts. I am trying to
write a macro whose expansion contains another macro, more precisely a
let-syntax form. My full example is attached below. In the first part,
I use a let-syntax directly. In the second part, I use a macro that
generates exactly the form that I wrote by hand in the first part -
but then the let-syntax seems to be ignored.

The macro stepper isn't of much help here. It shows the expansion
of (defn (foo2 ...)) into essentially what I wrote by hand for foo1,
and then declares the expansion finished.

Can anyone tell me (1) why this doesn't work and (2) how to fix it?

Thanks in advance,
  Konrad.

==
#lang racket

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

;
; this works fine
;
(define (foo1 x y)
  (let-syntax ([send (λ (stx)
   (syntax-parse stx
 ((send obj:expr method:id x:expr ...)
  #'(method obj x ...])
(send x + y)))

(foo1 2 3)

;
; this doesn't
;
(define-syntax (def stx)
  (syntax-parse stx
[(_ (fn-name:id arg:id ...) body ... )
 #'(define (fn-name arg ...)
 (let-syntax ([send (λ (stx)
  (syntax-parse stx
[(send obj:expr method:id x:expr (... ...))
 #'(method obj x (... ...))]))])
   body ...))]))

(def (foo2 x y)
  (send x + y))

(foo2 2 3)

;; send: target is not an object
;; ;   target: 2
;; ;   method name: +
;; ;

-- 
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.


Re: [racket-users] Macro-generating macros

2015-09-03 Thread Brian Mastenbrook
On Sep 3, 2015, at 11:44, Konrad Hinsen  wrote:

> Hi everyone,
> 
> Here's another plea for help from the macro experts. I am trying to
> write a macro whose expansion contains another macro, more precisely a
> let-syntax form. My full example is attached below. In the first part,
> I use a let-syntax directly. In the second part, I use a macro that
> generates exactly the form that I wrote by hand in the first part -
> but then the let-syntax seems to be ignored.
> 
> The macro stepper isn't of much help here. It shows the expansion
> of (defn (foo2 ...)) into essentially what I wrote by hand for foo1,
> and then declares the expansion finished.
> 
> Can anyone tell me (1) why this doesn't work and (2) how to fix it?

It's a capture problem. In the first case, you're just binding the name "send" 
locally and all is well. In the second case, you're trying to introduce a 
binding for "send" that you didn't get from the input form. You're also getting 
a confusing error because "send" is already bound; try using a name that's not 
already defined and you should get an unbound identifier.

You can fix this in one of two ways. Your `def' macro could take the name of 
the `send' macro it binds as a parameter, which gets a little ugly. 
Alternatively, you can use a syntax parameter, which is probably the ideal 
solution here.

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

(define-syntax-parameter send (lambda (stx) (raise-syntax-error 'send "send 
used out of context")))

(define-syntax (def stx)
 (syntax-parse stx
   [(_ (fn-name:id arg:id ...) body ... )
#'(define (fn-name arg ...)
(syntax-parameterize ([send (λ (stx)
  (syntax-parse stx
[(send obj:expr method:id x:expr (... 
...))
 #'(method obj x (... ...))]))])
 body ...))]))

(def (foo2 x y)
 (send x + y))

(foo2 2 3)


--
Brian Mastenbrook
br...@mastenbrook.net
http://brian.mastenbrook.net/

-- 
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.