On Apr 11, 2012, at 9:41 AM, Eli Barzilay wrote:

>> Is there a way to make (outer (outer x)) do the right thing while still 
>> using syntax parameters?
> 
> That's an obvious bait, right?
> 
>  (define-syntax (def stx)
>    (syntax-case stx ()
>      [(_ (name args ...) body ...)
>       #`(define name
>           (let-syntax
>               ([#,(datum->syntax stx 'outer stx)
>                 (λ (stx*)
>                   (syntax-case stx* ()
>                     [(_ id) (datum->syntax #'#,stx
>                                            (syntax->datum #'id)
>                                            stx*)]))])
>             (λ (args ...) body ...)))]))

Maybe I'm still a little groggy this morning, but where's the 
`syntax-parameterize'? That looks like the regular datum->syntax insertion 
based version of `def' to me.

(And yes, that was bait, but it was intended to highlight how much more 
complicated it would be to write this with syntax parameters.)

On Apr 11, 2012, at 9:48 AM, Eli Barzilay wrote:

> 
>> They don't compose very well, since as a macro author I can't use a
>> macro which uses syntax parameters without those parameters becoming
>> part of the interface of my own macro.
> 
> Right -- exactly like plain parameters.  (And you might as well not
> like them either.)
> 
>> The only way that I can see to avoid exposing this is to have `m'
>> carefully capture and restore the values of any parameters used by
>> `def', which is an extremely fragile solution.
> 
> (Same here -- I don't think that this is any more fragile than the
> same with plain parameters…)

I don't think the analogy between runtime parameters and syntax parameters is 
really exact, and I think there are differences between the two that make 
syntax parameters seem much more nonobvious than ordinary parameters.

One difference is that syntax parameters are much more like Common Lisp 
specials than they are Racket parameters in that the apparent binding of the 
identifier changes rather than the behavior of what the identifier is bound to. 
(Yes, I know that's not strictly speaking true in the sense of 
`free-identifer=?', but that actually makes syntax parameters seem even *more* 
freaky to me.) What this means in practice is that I *know* that 
(current-output-port) refers to the current value of a parameter, since I'm 
calling it, and there's no expectation that a called procedure return the same 
value every time. On the other hand, I am surprised if a simple variable 
reference in a macro refers to different bindings depending on where the macro 
is called.

Even a macro which when expanded twice with the same (free-identifier=? and 
bound-identifier=?) inputs returned different results would be surprising to 
me. Parameters are impure by design and are really quite helpful in certain 
impure contexts (I/O, for starters). Macros are usually expected to be pure.

I think macros which wrap around a body or an expression are much more common 
than higher-order-functions, and syntax parameters are intended to be used as a 
lexical convenience in these macros in situations where a function would never 
use a parameter. An anaphoric conditional or iteration construct is much more 
attractive and seemingly helpful than a version of `map' which uses a parameter 
instead of passing a value. I think we can all understand how confusing that 
version of `map' would be, but do we look at an anaphoric iteration construct 
which uses a syntax parameter in the same light?

I think the fact that Danny found the behavior of his macro to be surprising 
speaks for itself, and I'm wondering if other people feel the same way too.

--
Brian Mastenbrook
br...@mastenbrook.net
http://brian.mastenbrook.net/
____________________
  Racket Users list:
  http://lists.racket-lang.org/users

Reply via email to