Re: [racket-dev] Enhancement to the syntax system?

2014-05-03 Thread Marijn Schouten (hkBst)
On 07/10/2012 05:03 PM, Matthew Flatt wrote:
 At Tue, 10 Jul 2012 10:51:57 -0400, Eli Barzilay wrote:
 20 minutes ago, Marijn wrote:

 It seems to me that both these results cannot be correct
 simultaneously, but I'll await the experts' opinion on that.

 This does look weird:

   #lang racket
   (define-for-syntax (f stx) #`(let ([x 1]) #,stx))
   (define-syntax (m stx)
 (with-syntax ([zz (f #'x)]) #`(let ([x 2]) zz)))
   (m)

 evaluates to 1, but if I change the first two stx names into x
 *or* if I change the argument name for the macro to x, then it
 returns 2.
 
 It's natural --- but not correct --- to think that #` is responsible
 for hygiene, in which case `(f #'x)' should keep the given `x' separate
 from the `let'-bound `x' in the result.
 
 Instead, hygiene is the responsibility of macro invocation, and
 
  #`(let ([x 1]) #,#'x)
 
 is simply the same as
 
  #`(let ([x 1]) x)
 
 and so
 
  (f #'x)
 
 above is equivalent to
 
  #`(let ([x 1]) x)

IIUC then you're saying that also all the following (fx #'x) and (fy
#'x) are equivalent to #`(let ((x 0)) x), but if you run this code then
you will get a 0 result only for (myy), contrary to what I would expect
based on the above explanation.

#lang racket

(define-for-syntax (fx x) #`(let ((x 0)) #,x))
(define-for-syntax (fy y) #`(let ((x 0)) #,y))

(define-syntax (mxx x)
  (syntax-case x () ((_) #`(let ((x 99)) #,(fx #'x)

(define-syntax (mxy x)
  (syntax-case x () ((_) #`(let ((x 99)) #,(fy #'x)

(define-syntax (myx y)
  (syntax-case y () ((_) #`(let ((x 99)) #,(fx #'x)

(define-syntax (myy y)
  (syntax-case y () ((_) #`(let ((x 99)) #,(fy #'x)

(mxx)
(mxy)
(myx)
(myy)

==

99
99
99
0

Marijn



Re: [racket-dev] Enhancement to the syntax system?

2012-07-10 Thread Eli Barzilay
20 minutes ago, Marijn wrote:
 
 It seems to me that both these results cannot be correct
 simultaneously, but I'll await the experts' opinion on that.

This does look weird:

  #lang racket
  (define-for-syntax (f stx) #`(let ([x 1]) #,stx))
  (define-syntax (m stx)
(with-syntax ([zz (f #'x)]) #`(let ([x 2]) zz)))
  (m)

evaluates to 1, but if I change the first two stx names into x
*or* if I change the argument name for the macro to x, then it
returns 2.

-- 
  ((lambda (x) (x x)) (lambda (x) (x x)))  Eli Barzilay:
http://barzilay.org/   Maze is Life!



Re: [racket-dev] Enhancement to the syntax system?

2012-07-10 Thread Ludovic Courtès
Hi,

Matthew Flatt mfl...@cs.utah.edu skribis:

 It's natural --- but not correct --- to think that #` is responsible
 for hygiene, in which case `(f #'x)' should keep the given `x' separate
 from the `let'-bound `x' in the result.

[...]

 If you change the example to

  #lang racket
  (begin-for-syntax 
   (define-syntax-rule (f body)
 #`(let ([x 1]) body)))
  (define-syntax (m stx)
(with-syntax ([zz (f x)]) #`(let ([x 2]) zz)))
  (m)

 so that `f' is used as a macro instead of a function, then you get 2,
 since the macro-expansion of `(f x)' keeps the `x's separate.

Interesting.  Thanks for the clarification and examples.

Ludo’.



Re: [racket-dev] Enhancement to the syntax system?

2012-07-10 Thread Stefan Israelsson Tampe
samth made a pointer to

http://srfi.schemers.org/srfi-72/srfi-72.html

It does not look like guile racket etc. have implemented this yet.

Am I wrong?

This is precisely what I'm after!

On Tue, Jul 10, 2012 at 5:26 PM, Ludovic Courtès l...@gnu.org wrote:

 Hi,

 Matthew Flatt mfl...@cs.utah.edu skribis:

  It's natural --- but not correct --- to think that #` is responsible
  for hygiene, in which case `(f #'x)' should keep the given `x' separate
  from the `let'-bound `x' in the result.

 [...]

  If you change the example to
 
   #lang racket
   (begin-for-syntax
(define-syntax-rule (f body)
  #`(let ([x 1]) body)))
   (define-syntax (m stx)
 (with-syntax ([zz (f x)]) #`(let ([x 2]) zz)))
   (m)
 
  so that `f' is used as a macro instead of a function, then you get 2,
  since the macro-expansion of `(f x)' keeps the `x's separate.

 Interesting.  Thanks for the clarification and examples.

 Ludo’.




Re: [racket-dev] Enhancement to the syntax system?

2012-07-10 Thread Matthew Flatt
At Tue, 10 Jul 2012 10:51:57 -0400, Eli Barzilay wrote:
 20 minutes ago, Marijn wrote:
  
  It seems to me that both these results cannot be correct
  simultaneously, but I'll await the experts' opinion on that.
 
 This does look weird:
 
   #lang racket
   (define-for-syntax (f stx) #`(let ([x 1]) #,stx))
   (define-syntax (m stx)
 (with-syntax ([zz (f #'x)]) #`(let ([x 2]) zz)))
   (m)
 
 evaluates to 1, but if I change the first two stx names into x
 *or* if I change the argument name for the macro to x, then it
 returns 2.

It's natural --- but not correct --- to think that #` is responsible
for hygiene, in which case `(f #'x)' should keep the given `x' separate
from the `let'-bound `x' in the result.

Instead, hygiene is the responsibility of macro invocation, and

 #`(let ([x 1]) #,#'x)

is simply the same as

 #`(let ([x 1]) x)

and so

 (f #'x)

above is equivalent to

 #`(let ([x 1]) x)


If you change the example to

 #lang racket
 (begin-for-syntax 
  (define-syntax-rule (f body)
#`(let ([x 1]) body)))
 (define-syntax (m stx)
   (with-syntax ([zz (f x)]) #`(let ([x 2]) zz)))
 (m)

so that `f' is used as a macro instead of a function, then you get 2,
since the macro-expansion of `(f x)' keeps the `x's separate.




Re: [racket-dev] Enhancement to the syntax system?

2012-07-10 Thread Ryan Culpepper

On 07/10/2012 10:51 AM, Eli Barzilay wrote:

20 minutes ago, Marijn wrote:


It seems to me that both these results cannot be correct
simultaneously, but I'll await the experts' opinion on that.


This does look weird:

   #lang racket
   (define-for-syntax (f stx) #`(let ([x 1]) #,stx))
   (define-syntax (m stx)
 (with-syntax ([zz (f #'x)]) #`(let ([x 2]) zz)))
   (m)

evaluates to 1, but if I change the first two stx names into x
*or* if I change the argument name for the macro to x, then it
returns 2.


The difference between

(define-for-syntax (f1 stx) #`(let ([x 1]) #,stx)

and

(define-for-syntax (f2 x) #`(let ([x 1]) #,x)

is that the 'x' in the template in the 'f2' is not bound-identifier=? to 
the 'x' that appears in the template of 'm', because it has a rename 
wrap due to the 'x' formal parameter of 'f2'. That is, 'f2' behaves 
essentially the same as


(define-for-syntax (f2* x*) #`(let ([x* 1]) #,x*)

A likely mistake is to think that the wrap generated by the 'x' in 'f2' 
doesn't count because it happens before we get around to the real 
macro expansion that you care about. But that's not the case (at least 
in Racket).


A good rule of thumb is to never use local variable names in your macro 
implementation (including compile-time auxiliary functions) that also 
appear in the macro's template (including etc).


A related error is the identifier used out of context error that you 
get from, eg,


(define-syntax (m stx)
  (let ([+ *])
#'(+ 1 2)))
(m)  ;; = identifier used out of context in: +

The binding of '+' in the macro changes the meaning of the '+' in the 
template, even though the bindings exist at different phases. You could 
perhaps avoid this issue by changing the hygiene algorithm by adding a 
phase level to rename wraps and skipping different-phase rename wraps 
during resolution. I'm not sure if this is a good idea or if anyone has 
tried it.


Ryan



Re: [racket-dev] Enhancement to the syntax system?

2012-07-10 Thread Eli Barzilay
An hour and a half ago, Matthew Flatt wrote:
 
 It's natural --- but not correct --- to think that #` is responsible
 for hygiene, in which case `(f #'x)' should keep the given `x'
 separate from the `let'-bound `x' in the result.
 
 Instead, hygiene is the responsibility of macro invocation, and
 
  #`(let ([x 1]) #,#'x)
 
 is simply the same as
 
  #`(let ([x 1]) x)
 
 and so
 
  (f #'x)
 
 above is equivalent to
 
  #`(let ([x 1]) x)
 
 
 If you change the example to
 
  #lang racket
  (begin-for-syntax 
   (define-syntax-rule (f body)
 #`(let ([x 1]) body)))
  (define-syntax (m stx)
(with-syntax ([zz (f x)]) #`(let ([x 2]) zz)))
  (m)
 
 so that `f' is used as a macro instead of a function, then you get 2,
 since the macro-expansion of `(f x)' keeps the `x's separate.

Yeah, I think that this kind of confusion is there, but it's easy (at
least relatively easy) to build a mental model of how things work
and avoid such problems -- but the tricky bit here is that things
break when the `stx' is renamed to `x'.


50 minutes ago, Ryan Culpepper wrote:
 
 The difference between
 
 (define-for-syntax (f1 stx) #`(let ([x 1]) #,stx)
 
 and
 
 (define-for-syntax (f2 x) #`(let ([x 1]) #,x)
 
 is that the 'x' in the template in the 'f2' is not bound-identifier=? to 
 the 'x' that appears in the template of 'm', because it has a rename 
 wrap due to the 'x' formal parameter of 'f2'. That is, 'f2' behaves 
 essentially the same as
 
 (define-for-syntax (f2* x*) #`(let ([x* 1]) #,x*)

Yeah, I think that this is the more confusing bit.  (I suspected
something along this line, but didn't have time to figure out a good
explanation...)  So I think that the real confusion is actually a
combination of what Matthew pointed at in the above and this one,
making the result trickier than both.  In other words, I *think* that
the effect of the transformer's argument name makes it looks like the
#` *was* responsible for hygiene when it's actually just this point
that makes it happen...  (This is all IIUC.)


 A likely mistake is to think that the wrap generated by the 'x' in
 'f2' doesn't count because it happens before we get around to the
 real macro expansion that you care about. But that's not the case
 (at least in Racket).
 
 A good rule of thumb is to never use local variable names in your
 macro implementation (including compile-time auxiliary functions)
 that also appear in the macro's template (including etc).

Yeah, and a subtle lesson here is that `stx' is a useful convention.
(I think that `x' is common in some guile code, so this would be a
point for them.)


 A related error is the identifier used out of context error that
 you get from, eg,
 
 (define-syntax (m stx)
(let ([+ *])
  #'(+ 1 2)))
 (m)  ;; = identifier used out of context in: +
 
 The binding of '+' in the macro changes the meaning of the '+' in
 the template, even though the bindings exist at different
 phases. You could perhaps avoid this issue by changing the hygiene
 algorithm by adding a phase level to rename wraps and skipping
 different-phase rename wraps during resolution. I'm not sure if this
 is a good idea or if anyone has tried it.

(And this is what Matthew's last example gets by changing `f' to a
macro, right?  Also, Stefan posted a related message to the
scheme-reports list where he imlpemented some new #. thing which is
(roughly speaking) something that expands to a `let-syntax' and
therefore tries to do the same.)

In any case, it would be nice if the original example I posted (which
is a variant of what was discussed originally) would throw an error
instead of looking right in a way that is wrong...

-- 
  ((lambda (x) (x x)) (lambda (x) (x x)))  Eli Barzilay:
http://barzilay.org/   Maze is Life!