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

2014-05-13 Thread Marijn Schouten (hkBst)
I realize this is a very old thread, but the behavior of Racket has not
changed since.

On 03-05-14 23:29, Marijn Schouten (hkBst) wrote:
 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
 _
   Racket Developers list:
   http://lists.racket-lang.org/dev
 

_
  Racket Developers list:
  http://lists.racket-lang.org/dev


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

2014-05-13 Thread Matthew Flatt
The difference between

 (define-for-syntax (fx x) #`(let ((x 0)) #,x))
^---*

and

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

is that the `x` of `(let ((x ...)))` gets lexical context from the `x`
argument to `fx`, but there's no such binding for the context of `x`
within `fy`.

The `x` in the `let` form generated by `fx` will only bind others `x`s
that also have the same context. So, it won't bind `x` passed as

 (fx #'x)

since that `x` doesn't have the argument of `fx` in its context.

To get an `x` from the inside of `fx`, you could pull it out of the
result of a call to `fx`:

  (syntax-case (fx #'y) ()
[(let ([var rhs]) body)
 ;; #'var is `x` from the inside of `fx`:
 (fx #'var)])


A case could be made that the `x` of `(let ((x ...)))` shouldn't have
anything to do with the `x` argument of `fx`, because they live in
different phases. There's a trade-off between allowing different
bindings in different phases and providing a more useful error message
when a binding is accidentally used in the wrong phase.


At Tue, 13 May 2014 14:44:43 +0200, Marijn Schouten (hkBst) wrote:
 I realize this is a very old thread, but the behavior of Racket has not
 changed since.
 
 On 03-05-14 23:29, Marijn Schouten (hkBst) wrote:
  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
  _
Racket Developers list:
http://lists.racket-lang.org/dev
  
_
  Racket Developers list:
  http://lists.racket-lang.org/dev


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
_
  Racket Developers list:
  http://lists.racket-lang.org/dev


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!
_
  Racket Developers list:
  http://lists.racket-lang.org/dev


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.

_
  Racket Developers list:
  http://lists.racket-lang.org/dev


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
_
 Racket Developers list:
 http://lists.racket-lang.org/dev


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


_
  Racket Developers list:
  http://lists.racket-lang.org/dev


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

_
  Racket Developers list:
  http://lists.racket-lang.org/dev


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!
_
  Racket Developers list:
  http://lists.racket-lang.org/dev


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

2012-07-10 Thread Stefan Israelsson Tampe
The question I posed was If it's possible to use srfi-72 in guile or
racket. It is indeed a wish
of mine that it's implemented because it will most certainly help me write
beutiful code because
that srfi cater to the coding style Ichoose to have. Without it one most
certainly need to use with-syntax to introduce the bindings in order to be
safe and avoid a multiple of possible syntactic loopholes as can see if you
read André van Tonder's

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

Anyway one does not need to change psyntax in order to come close to that
system. A more hacky
way is to use code like the one at the end of this document. It's a
reiteration and improvement on a
previous version. So with this hack I can write,

-
(use-modules (syntax unquote++))
(define (f x y) #`(let ((x 1)) (+ #,x #,y)))
(define (h y) ##`(let ((x 2)) #.((x) (f x y
(define-syntax g (lambda (x) (syntax-case x () ((_ y) ##`(let ((x y))
#.((x) (h x)))
scheme@(guile-user) (g 3)
$2 = 5

--
In racket,
(define-for-syntax (f x y) #`(let ((x 1)) (+ #,x #,y)))
(define-for-syntax (h y) #`(let ((x 2)) #,(f #'x y))
(define-syntax (g stx) (syntax-case stx () ((_ y) #`(let ((x y)) #,(h
#'x)
 (g 3)
4
--

This shows that it was just luck previously when racket produced the
correct (for my intention) answer.
with srfi-72 a correct answer would have been produced. Without srfi-72 I
will then move over to use
##` and #. in my code because it will be easy to transfer later on if when
srfi-72 is available in some form.

/Stefan

(define-module (syntax unquote++)
  #:export (quasisyntax++ insyntax))

(define *s* (make-fluid '()))
(define *t* (make-fluid '()))

(define table (make-weak-key-hash-table))
(define (add-lambda lam)
  (let* ((id (gensym id))
 (x  (datum-syntax #'table id)))
(hashq-set! table id lam)
x))
(define (plexer x . l)
  (let ((lam (hashq-ref table x)))
(apply lam l)))

(define (parse stx x)
  (syntax-case x (unsyntax insyntax unsyntax-splicing)
((unsyntax  . _) x)
((unsyntax-splicing . _) x)
((insyntax ((p ...) c ...))
 (with-syntax ((g (datum-syntax stx (gensym g)))
   (i (datum-syntax stx (gensym i
   (fluid-set! *s* (cons #'(g (lambda (x)
(syntax-case x ()
  ((_ p ...) (plexer 'i #'p ...)
 (fluid-ref *s*)))
   (fluid-set! *t* (cons #'(i (add-lambda
   (lambda (p ...) (begin c ...
 (fluid-ref *t*)))
   #'(g p ...)))
((x . l)
 (cons (parse stx #'x) (parse stx #'l)))
(x #'x)))

(define-syntax quasisyntax++
  (lambda (x)
(syntax-case x ()
  ((_ y)
   (begin
 (fluid-set! *s* '())
 (fluid-set! *t* '())
 (with-syntax ((statement (parse x #'y))
   (lets  (fluid-ref *s*))
   (withs (fluid-ref *t*)))
   #'(with-syntax withs
   #`(let-syntax lets statement

(define (rg ch stream)
  (let ((x (read-char stream)))
(cond
 ((eqv? x #\`)
  `(quasisyntax++ ,(read stream)))
 (#t
  (error Wrong format of # reader extension)

(define (rg. ch stream) `(insyntax ,(read stream)))

(read-hash-extend #\# rg)
(read-hash-extend #\. rg.)
_
  Racket Developers list:
  http://lists.racket-lang.org/dev