[racket] for/hash: bad syntax in: for/hash [and 1 more messages]

From: Marijn (hkBst at gentoo.org)
Date: Thu Jan 5 06:01:35 EST 2012

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 04-01-12 22:50, Eli Barzilay wrote:
> 11 hours ago, Marijn wrote:
>> It took me a while to understand what you're saying here, but if
>> I am not mistaken you're saying that the result of the
>> macro-expansion is a function-application with `let*' (or
>> `for/hash') in the function position. Then when #%app looks that
>> name up in the environment it doesn't find anything and thus
>> complains about it. What I would then expect is that it complains
>> about an undefined variable `let*'.
> 
> There is no such lookup at runtime.  Your code *does* expand into
> a `let*' (or to `for/hash' in the original case), it just expands
> into a non-parenthesized reference to it, which invokes the macro
> transformer with just the identifier -- same as if you'd write (+
> let* 3).
> 
> 
>>> 5. And BTW, the reason it doesn't work is that the first
>>> expansion gets to
>>> 
>>> ((with-variables let*) (with-variables ((y 1)))
>>> (with-variables 2))
>>> 
>>> and this form is not a macro -- so it's expanded as a function
>>>  call,
>>> 
>>> (#%app ...same...)
>>> 
>>> and the rest is obvious.
>> 
>> It's not so obvious to me why this should degenerate into a
>> function call; I'd say it depends on the result of
>> (with-variables let*).
> 
> This is not a kind of "degeneration".  Here's a possibly simpler
> to follow example:
> 
> -> (define-syntax foo (syntax-rules () [(foo (x y z)) ((foo x) (foo
> y) (foo z))] [(foo x) x])) -> (foo (+ 1 2)) 3 -> (foo (when 1 2)) ;
> stdin:19:6: when: bad syntax in: when [,bt for context]
> 
> Here's what happens when macro expansion sees (foo (+ 1 2)):
> 
> 1. It recognizes it as a use of the `foo' macro, and calls your 
> expander which returns
> 
> ((foo +) (foo 1) (foo 2))
> 
> 2. Since this is not a macro (it doesn't begin with a known (or
> any) identifier), it (roughly) interprets it as a function call,
> which in Racket means that you now have:
> 
> (#%app (foo +) (foo 1) (foo 2))

Yes, this is the step I wonder at. Since foo is a macro (foo +) may
expand into a reference to a macro. Why choose semantics that
explicitly exclude/invalidate that case? If it turns out (foo +)
doesn't expand to a reference to a macro isn't there still plenty of
time to insert `#%app'?

> At this point it's probably tempting to say that the `foo' macro 
> behaves well only when you hand it expressions that do not involve 
> macros.  This is a dangerous assumption, since there might be
> forms that look like plain applications but are really
> macro-expanded -- like applying a contracted function (which is,
> IIRC, implemented as a macro to give source information).  In these
> cases you'd lose such special treatment.

This seems to be an artifact of the above choice to exclude certain
possibilities.

> But an even more subtle point is when you mix languages: the above 
> seemingly fine case of (foo (+ 1 2)) can be broken since it uses 
> whatever application means in whatever module the `foo' definition 
> appears at.  If, for example, you use it in a language that has a 
> different meaning for applications (like the lazy language), then
> the result will be confusing in that you'd get the meaning from
> `foo's module.

Idem ditto here. If you don't read `foo' as having an invisible #%app
in its definition (lexically bound to whatever #%app is in that
module), then this problem doesn't exist.

Thanks for your other comments.

Marijn
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.18 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk8Fgw8ACgkQp/VmCx0OL2zs5ACgoaapvYmWpFDjHJ+BLiI+W+rn
rOMAoK4yYrX7p4s7z0agUJ+yUuzoznRV
=2wdp
-----END PGP SIGNATURE-----


Posted on the users mailing list.