Re: syntax-local-binding

2012-01-25 Thread Andy Wingo
Hello Mark,

On Wed 25 Jan 2012 03:30, Mark H Weaver m...@netris.org writes:

 Perhaps, though, at this point we're just going to have to agree to
 disagree;

 This is a euphemism for sorry, but we're doing it my way.

Just a few days ago, you said:

On Sun 22 Jan 2012 13:23, Mark H Weaver m...@netris.org writes:

 If Andy finishes his version of `local-eval', that's all well and good,
 and I'm happy to use his version.

You got a fairly explicit NAK from me on the-environment in psyntax:
beginning with suggestions for a different approach, continuing where I
implemented those suggestions, and finally just a few days ago.  (I.e.,
I do not consent to the-environment in psyntax, given the existence of
other possibilities.)

But, you are interested in local-eval in 2.0.4, and you consented to
this approach.

Please.  Let us focus on solutions.

Regards,

Andy
-- 
http://wingolog.org/



Re: syntax-local-binding

2012-01-25 Thread Ludovic Courtès
Hello Happy Guilers!  :-)

Sorry for remaining silent in this heated thread (I spent my spare time
on other practical issues for 2.0.4, and felt I lacked the competence.)

My overall feeling is that providing a 1.8-compatible ‘local-eval’ in
2.0 is great, but that it’s essentially one bug to be fixed among many
others.

Thus, I appreciate all the work Andy and you have put into it, and I’m
glad it will be helpful to Guile users such as Lilypond.  However, I
think, that we should keep in mind that Guile is not just about
‘local-eval’, and that there are other great things to work on together.

As for the technical aspects:

Mark H Weaver m...@netris.org skribis:

 Andy Wingo wi...@pobox.com writes:
 On Tue 24 Jan 2012 14:25, Mark H Weaver m...@netris.org writes:

 Andy Wingo wi...@pobox.com writes:

 None of the interfaces that I proposed leak internal psyntax
 representations.

 `syntax-local-binding' leaks the internal representations used for
 bindings.

 You mean, whether something is a lexical, or a macro, or a global, or
 whatever; OK.

 That's actually not what I meant, although I'm not convinced that we
 fully understand the implications of exposing even that much.  One thing
 that is already clear is that `identifier-syntax' and `local-eval' were
 previously capable of emulating variables perfectly before, whereas in
 the presence of `syntax-local-binding' they no longer are.

 This is a perfect example of how added flexibility in one aspect can
 lead to _reduced_ flexibility in other aspects.  I think we need more
 time to consider the implications of this.

I agree.  Yet, it’s the kind of API that is useful internally for
different purposes beyond ‘local-eval’, as this discussion showed,
right?

So, IIUC, the tension is:

  1. Such as API is desirable for Guile-internal consumption.

  2. Exposing it to users may restrict our ability to change the
 implementation in the future, just like ‘the-environment’ did.

I haven’t fully thought about it, but one possible trade-off would be to
mark ‘syntax-local-binding’  co. as internal, somehow arrange to make
them visible only from some (system ...) module, and document them in
the “Implementation” chapter.

WDYT?

Thanks,
Ludo’.




Re: syntax-local-binding

2012-01-25 Thread Mark H Weaver
I have nothing new to say here, so I'll spare you all my increasingly
frustrated repetitions.  I need to walk away for a while.  Do what you
feel is best.  Good luck.

  Mark



Re: syntax-local-binding

2012-01-24 Thread David Kastrup
Peter TB Brett pe...@peter-b.co.uk writes:

 It seems pretty clear to me that the only (debatable) downside to
 using Mark's implementation is that some definitions end up in the
 wrong module, while your implementation has several potentially
 *major* problems (including the necessity of providing universally
 unique gensyms) which Mark has managed to avoid.

Let me just repeat that I consider universally unique gensyms a recipe
for trouble.  Having a compiler _depend_ on creating unreproducible
output is going to be in the not really fun category for a _lot_ of
things.  I don't have much of a clue about the other differences.  But
this one _really_ comes at a dear price in its implications.

-- 
David Kastrup




Re: syntax-local-binding

2012-01-24 Thread Andy Wingo
Hi Mark,

On Tue 24 Jan 2012 03:11, Mark H Weaver m...@netris.org writes:

 you seem unabashedly content to lock us into using psyntax forever,

This statement is an exaggeration.  While I am content with psyntax now,
all change is possible, with time.  While it's important to think of the
future (and the past), one must not forget about the present :)

 It concerns me when I see internal psyntax representations exported in
 our API.

None of the interfaces that I proposed leak internal psyntax
representations.

syntax-local-binding provides binding information for an identifier.
Racket provides similar procedures, and does not use psyntax.  Therefore
this information does not tie us to the psyntax implementation.

syntax-locally-bound-identifiers can be implemented in any expander.  It
provides syntax objects.  Syntax objects are not a psyntax
implementation detail.

syntax-module is a simple accessor.  Racket provides the same accessor.
Therefore it does not leak psyntax implementation details.

 If we can already foresee the need to deprecate an interface, wouldn't
 it be better not to add it in the first place?

I don't see the need to deprecate them now, not more than any other
identifier that we export.

 I just have one final request: please at least change the lexical
 environments in your `local-eval' implementation to use the future-proof
 `evaluator procedure' representation, as I have done in mine.

For the reasons I mentioned in my mail yesterday at 12:52 UTC, I really
don't see the point, as we have more effective means of dealing with
future change than introducing an abstraction there.  But if it will
make you happy, sure.  I'm quite tired of this topic ;-)

Regards,

Andy
-- 
http://wingolog.org/



Re: syntax-local-binding

2012-01-24 Thread Mark H Weaver
Andy Wingo wi...@pobox.com writes:

 On Tue 24 Jan 2012 11:30, Peter TB Brett pe...@peter-b.co.uk writes:

 It seems pretty clear to me that the only (debatable) downside to using
 Mark's implementation is that some definitions end up in the wrong
 module, while your implementation has several potentially *major*
 problems (including the necessity of providing universally unique
 gensyms)

 Let's be clear here: the universally-unique gensym issue is something
 that Guile *already* has, in version 2.0.0, 2.0.1, etc.

I don't see why we need universally-unique gensyms unless your approach
to `local-eval' is used.  I've already explained why they are not needed
for macros compiled in another session.

 It concerns me when I see internal psyntax representations exported in
 our API.

 None of the interfaces that I proposed leak internal psyntax
 representations.

`syntax-local-binding' leaks the internal representations used for
bindings.  I gave an example where this would constrain our ability to
change the binding representation for syntactic keywords, and your
response was to point out that my particular example could be done in a
different way without changing the representation.  Your response
demonstrated the weakness of my particular example, while underscoring
my main point: that this constrains our internal representation choices.

 I just have one final request: please at least change the lexical
 environments in your `local-eval' implementation to use the future-proof
 `evaluator procedure' representation, as I have done in mine.

 For the reasons I mentioned in my mail yesterday at 12:52 UTC, I really
 don't see the point, as we have more effective means of dealing with
 future change than introducing an abstraction there.

Your suggested more effective means is to introduce a new type
lexical-environment-2 and continue supporting lexical-environment.
No thanks.

 But if it will make you happy, sure.  I'm quite tired of this topic
 ;-)

Yes, it would make me happy, thank you.  And believe me, I'm tired of
this topic too.  I thought I was mostly finished working on `local-eval'
three weeks ago, when I produced my simple patch, which I _still_ think
is superior to yours in the most important respect, namely in the
commitments that it forces us to make.

Regards,
  Mark



Re: syntax-local-binding

2012-01-24 Thread Noah Lavine
Hello,

 If we can already foresee the need to deprecate an interface, wouldn't
 it be better not to add it in the first place?

 I don't see the need to deprecate them now, not more than any other
 identifier that we export.

I think this may be the key to this argument. There are two separate
questions being debated as one question. Here they are:

1. Do we forsee a need to deprecate the syntax-local-binding
functionality in the future, for instance to move away from psyntax?
2. Is this version of syntax-local-binding the best interface to this
functionality?

They are related questions, but they are distinct because someone
could believe that it is good to expose this functionality but that
the current syntax-local-bindings is not the best interface for us.

I could be wrong, but I think that Andy answers maybe, but not for a
long time to 1, and therefore thinks it's fine to include
syntax-local-binding. Mark answers maybe, but definitely needs more
thought before we make a commitment to 2, and therefore does not want
to include syntax-local-binding. These are not contradictory
positions. (Some of their other positions are contradictory, though
:-) ). However, it does make me think that we should discuss the
interface to syntax-local-binding more before releasing it (but don't
take this too seriously, because I didn't follow the earlier threads
much).

Noah



mark uniqueness (Was: Re: syntax-local-binding)

2012-01-24 Thread Andy Wingo
On Tue 24 Jan 2012 14:25, Mark H Weaver m...@netris.org writes:

 I don't see why we need universally-unique gensyms
 I've already explained why they are not needed
 for macros compiled in another session.

Ah, I forgot to reply to that.  I found it:

On Mon 16 Jan 2012 14:28, Mark H Weaver m...@netris.org writes:

 The reason it has not been a problem with macros is that, within a
 top-level macro (which are the only ones used across Guile sessions),
 the only syntax-objects that can be meaningfully _introduced_ into the
 expansion are top-level/module bindings.  But these bindings have no
 associated labels or gensyms, because they're not in the wrap.

 See how this is a problem now where it wasn't before?
 Or am I missing something?

Either you are missing something, or I am, or both of us -- that much is
clear ;-)

Psyntax associates marks with every identifier.  Two identifiers are
equal if they are symbolically equal, and they have the same marks.  It
would break hygiene if two identifiers that didn't come from the same
place accidentally had the same marks.

A fresh mark is placed on syntax returned from a macro expander, if the
syntax was not present in the input.  An easy way to do this would be
simply:

  (define-syntax-rule (fresh-identifier)
#'x)
  (define my-id (fresh-identifier))

All you need to do is to introduce that binding into a macro, and you
might alias some other binding, because you have serialized the symbol
and marks into a compiled file.

This is admittedly far-fetched.  But it can happen, and at the
top-level.  For example, our old friend:

  (define-syntax-rule (define-const x val)
(begin
  (define t val)
  (define-syntax x (identifier-syntax t

Here, `t' will have a fresh mark.

Now, if in one compilation unit, I do:

  (define-const x 10)

And in another, I do:

  (let ((t 20))
x) = ?

You would expect the result to be 20.  But I think it could be 20, if
the marks on the two ts happened to collide.

Am I missing something? :-)

Andy
-- 
http://wingolog.org/



Re: syntax-local-binding

2012-01-24 Thread Andy Wingo
Hello Mark :)

Thanks again for your deep thoughts.  This conversation is a bit
stressful for the both of us, but we wouldn't be having it if we didn't
both care about Guile.

In the spirit of diffusing tension here, feel free to imagine all of my
words as coming from Mr. Collins for the duration of this thread ;-)

On Tue 24 Jan 2012 14:25, Mark H Weaver m...@netris.org writes:

 Andy Wingo wi...@pobox.com writes:

 None of the interfaces that I proposed leak internal psyntax
 representations.

 `syntax-local-binding' leaks the internal representations used for
 bindings.

You mean, whether something is a lexical, or a macro, or a global, or
whatever; OK.  I think that leak is the wrong word here: leaks are
inadvertent, whereas providing this information is what this function
was designed to do; and furthermore it's not a detail of psyntax (cf
Racket which does not use psyntax).

Let me offer another example of its utility: writing a macro stepper.
Again, for an example I'll have to link to the PLT folks' great work:

  http://docs.racket-lang.org/macro-debugger/index.html

With syntax-local-binding, syntax-locally-bound-identifiers, and a
couple hooks that get fired when a macro is expanded and reconstructed,
you could implement a macro stepper for Guile.

And, once we provide those hooks, you can implement this in a module.

Pretty sweet, if you ask me!

Perhaps, though, at this point we're just going to have to agree to
disagree; surely we have plumbed the depths sufficiently.  It's not
satisfying, but I think we both made a great effort to communicate and
convince -- and in some cases, to work on each other's code.  We really
need to move on here.  I will re-post my patches taking into account
your comments regarding the form of the environments.

Regards,

Andy
-- 
http://wingolog.org/



Re: syntax-local-binding

2012-01-24 Thread Mark H Weaver
Andy Wingo wi...@pobox.com writes:
 In the spirit of diffusing tension here, feel free to imagine all of my
 words as coming from Mr. Collins for the duration of this thread ;-)

Hehe :)

 On Tue 24 Jan 2012 14:25, Mark H Weaver m...@netris.org writes:

 Andy Wingo wi...@pobox.com writes:

 None of the interfaces that I proposed leak internal psyntax
 representations.

 `syntax-local-binding' leaks the internal representations used for
 bindings.

 You mean, whether something is a lexical, or a macro, or a global, or
 whatever; OK.

That's actually not what I meant, although I'm not convinced that we
fully understand the implications of exposing even that much.  One thing
that is already clear is that `identifier-syntax' and `local-eval' were
previously capable of emulating variables perfectly before, whereas in
the presence of `syntax-local-binding' they no longer are.

This is a perfect example of how added flexibility in one aspect can
lead to _reduced_ flexibility in other aspects.  I think we need more
time to consider the implications of this.

However, the more serious problem, and the one I was actually talking
about, is the _second_ value returned by `syntax-local-binding', which
exposes the representations of bindings stored in the cdrs of the
psyntax `r' alist.

 Let me offer another example of its utility: writing a macro stepper.

It's not the least bit surprising that exposing internal implementation
details enables the creation of all kinds of nifty things as external
programs that would ordinarily need to be internal.  This is perfectly
obvious.

However, as you wisely said to me when I posted my first `local-eval'
evaluator-only implementation, this stuff has a cost, and it has to
justify itself.  I assumed you meant the maintenance cost of supporting
this advanced functionality indefinitely, and the constraints that it
places on the freedom of future implementors.  Was I right?

In retrospect, based on your recent behavior, I wonder if that's what
you meant or if you were talking about something completely different,
because you seem to have completely abandoned your original restraint,
and have now gone much farther than I would ever dare to go.  Indeed, as
you can see, I am very unhappy about how far you have gone with this.

 Perhaps, though, at this point we're just going to have to agree to
 disagree;

This is a euphemism for sorry, but we're doing it my way.  Multiple
people here have expressed grave concerns about your approach, and not a
single person has publicly expressed their support for adding all of
these new interfaces you've designed.  Even Ludovic has remained silent.
And yet you apparently intend to rush all of this stuff into 2.0.4.
After all, nothing could be worse than having `the-environment' in
psyntax, even for single release.

Is this your idea of a consensus process, which you so often advocate?

 Mark



Re: syntax-local-binding

2012-01-23 Thread Andy Wingo
Heya Mark,

On Fri 20 Jan 2012 23:03, Mark H Weaver m...@netris.org writes:

   (let ((x 1))
 (syntax-local-binding #'x))

 is not equivalent to:

   (let ((x 1))
 (local-eval '(syntax-local-binding #'x) (the-environment)))

Indeed; bummer!  I think, though, that this is simply a consequence of
giving more power to macro writers.

It is analogous in some ways to the changes that identifier-syntax
introduce into macro writing: with identifier-syntax, one can no longer
write a code walker with syntax-rules pattern matching, as single
identifiers may expand out to complicated expressions, possibly even
with side effects.

 Why do you think that?  The procedures do carry metadata; I understood
 that that was your strategy, to use the serialization of the
 syntax-rules form in the procedure metadata.

 Well, this was in the context of a new strategy where psyntax would
 include a new core form called `call-with-current-local-expander' that
 calls its parameter (a procedure or macro) with a procedure that accepts
 an expression and returns an expanded form.  In this case, the most
 straightforward implementation would simply serialize the (r w mod)
 structures directly.

 Toward that end, I was thinking it would be nice to keep those
 structures serializable.  The only part that's not currently
 serializable are the transformer procedures for local macros.
 Thus the change in representation.

I have been staring at this empty page here for a little while, writing
and re-writing, but I can't get over a feeling that I really don't want
this kind of work in psyntax itself.  Who knows, maybe you have really
convincing arguments here, but this particular argument should not be
driving a decision about e.g. including syntax-local-binding or not.

That sounds negative, and in a way of course it is -- but still, I'd
much rather enable people to make powerful syntactic abstractions like
local-eval outside psyntax.  Syntax-parse, for example, if it ever
lands, will land in the form of a module

In this case there are lots of strategies you could use.  We could
change psyntax to embed the syntax objects in the procedure meta-data,
like I said.  Ice-9 local-eval could #:replace its own syntax-rules.  We
could (and probably should) do procedure serialization.

Regards,

Andy
-- 
http://wingolog.org/



Re: syntax-local-binding

2012-01-23 Thread Mark H Weaver
Andy Wingo wi...@pobox.com writes:

 On Fri 20 Jan 2012 23:03, Mark H Weaver m...@netris.org writes:

   (let ((x 1))
 (syntax-local-binding #'x))

 is not equivalent to:

   (let ((x 1))
 (local-eval '(syntax-local-binding #'x) (the-environment)))

 Indeed; bummer!  I think, though, that this is simply a consequence of
 giving more power to macro writers.

 It is analogous in some ways to the changes that identifier-syntax
 introduce into macro writing: with identifier-syntax, one can no longer
 write a code walker with syntax-rules pattern matching, as single
 identifiers may expand out to complicated expressions, possibly even
 with side effects.

This is false.  Macros are always expanded _before_ any of their
arguments are expanded.  Therefore, a code walker sees the unexpanded
forms, including any simulated variables bound by identifier-syntax.

 Why do you think that?  The procedures do carry metadata; I understood
 that that was your strategy, to use the serialization of the
 syntax-rules form in the procedure metadata.

 Well, this was in the context of a new strategy where psyntax would
 include a new core form called `call-with-current-local-expander' that
 calls its parameter (a procedure or macro) with a procedure that accepts
 an expression and returns an expanded form.  In this case, the most
 straightforward implementation would simply serialize the (r w mod)
 structures directly.

 Toward that end, I was thinking it would be nice to keep those
 structures serializable.  The only part that's not currently
 serializable are the transformer procedures for local macros.
 Thus the change in representation.

 I have been staring at this empty page here for a little while, writing
 and re-writing, but I can't get over a feeling that I really don't want
 this kind of work in psyntax itself.

Your priorities are reversed from what they ought to be.

What you _should_ be worried about is making commitments in our API that
we must continue to support forever.  This is a _real_ problem, since it
constrains our ability to modify our implementation in the future.

Putting the `the-environment' in psyntax is, at worst, a stylistic
issue.  Whether it belongs there is a matter of taste, but however
strongly you may feel about that, it is a purely _internal_
implementation issue.  The really important thing is that it commits us
to _nothing_.  There's nothing stopping us from radically reimplementing
it later.  In particular, there's nothing stopping us from moving it out
of psyntax later.

Guile has been in existence for a couple of decades already, and I hope
that it will be actively used for many decades to come.  With that in
mind, please consider the long view.  One of the reasons Scheme has
lasted so long is because it tries exceptionally hard to hide internal
implementation details.  Implementations that expose too much internal
detail may derive a short-term benefit from doing so, but it comes at
the price of eventual calcification: there comes a time when
implementations that expose too much become unable to make significant
internal structural changes.

Please consider this.  I feel that your mind has become closed to my
arguments.

 Mark



Re: syntax-local-binding

2012-01-23 Thread Andy Wingo
Hi Mark,

On Mon 23 Jan 2012 22:03, Mark H Weaver m...@netris.org writes:

 Andy Wingo wi...@pobox.com writes:

 with identifier-syntax, one can no longer write a code walker with
 syntax-rules pattern matching, as single identifiers may expand out
 to complicated expressions, possibly even with side effects.

 This is false.  Macros are always expanded _before_ any of their
 arguments are expanded.  Therefore, a code walker sees the unexpanded
 forms, including any simulated variables bound by identifier-syntax.

I'm not sure we're talking about the same thing here; do see Alex
Shinn's NAK on R6RS:  http://www.r6rs.org/ratification/results.html#X70

While I disagree with his assessment of the identifier-syntax tradeoff,
I think he correctly identifies it as a tradeoff.

 Why do you think that?  The procedures do carry metadata; I understood
 that that was your strategy, to use the serialization of the
 syntax-rules form in the procedure metadata.

 Well, this was in the context of a new strategy where psyntax would
 include a new core form called `call-with-current-local-expander' that
 calls its parameter (a procedure or macro) with a procedure that accepts
 an expression and returns an expanded form.  In this case, the most
 straightforward implementation would simply serialize the (r w mod)
 structures directly.

 Toward that end, I was thinking it would be nice to keep those
 structures serializable.  The only part that's not currently
 serializable are the transformer procedures for local macros.
 Thus the change in representation.

 I have been staring at this empty page here for a little while, writing
 and re-writing, but I can't get over a feeling that I really don't want
 this kind of work in psyntax itself.

 Your priorities are reversed from what they ought to be.

 What you _should_ be worried about is making commitments in our API that
 we must continue to support forever.  This is a _real_ problem, since it
 constrains our ability to modify our implementation in the future.

I know I'm going to sound like Mr. Collins in Pride and Prejudice here,
but I flatter myself that I know a thing or two about managing change --
I mean, replacing the lazy-memoizing evaluator with the compiler,
retrofitting psyntax into Guile, the whole subr mess, etc.  There is
always room to improve, of course, as in all human endeavor, but for now
it does seem that Guile is getting more powerful _and_ more limpid over
time.

But frankly though, regarding change, while we do need the freedom to
modify some things, some other practical freedoms just don't make the
cost/benefit cut, for me.  For example, considering replacing psyntax,
which seems to be in the back of your mind here.  This conservatism is
preventing Guile from adding features.  And we do need features --
local-eval and syntax-parse among them.

 Putting the `the-environment' in psyntax is, at worst, a stylistic
 issue.  Whether it belongs there is a matter of taste, but however
 strongly you may feel about that, it is a purely _internal_
 implementation issue.  The really important thing is that it commits us
 to _nothing_.  There's nothing stopping us from radically reimplementing
 it later.  In particular, there's nothing stopping us from moving it out
 of psyntax later.

Apart from the fact with `the-environment' in psyntax, it's in the
default environment, of course; though with autoloads one can get around
that...

With `the-environment' in a module, in 2.0.4 we could have three
functions added to psyntax:  syntax-local-binding,
syntax-locally-bound-identifiers, and syntax-module.  The first and the
third have precedent in Racket (whose hackers have been able to do
significantly awesome stuff).  The second is strange, but seems OK.  I'm
OK with them.

But what if they're the wrong interface?

Well, then we use the normal deprecation mechanism to get rid of them,
eventually (in the 2.2 series, for example).  We learned something.
Users get warned off the code.  Life goes on.

 Guile has been in existence for a couple of decades already, and I hope
 that it will be actively used for many decades to come.

Hear, hear.

 With that in mind, please consider the long view.  One of the reasons
 Scheme has lasted so long is because it tries exceptionally hard to
 hide internal implementation details.  Implementations that expose too
 much internal detail may derive a short-term benefit from doing so,
 but it comes at the price of eventual calcification: there comes a
 time when implementations that expose too much become unable to make
 significant internal structural changes.

 Please consider this.  I feel that your mind has become closed to my
 arguments.

I really do value your work, and your words, Mark.  Besides that
personal appreciation, I think you're doing good work for Guile.

We happen to disagree here on a matter of implementation.  OK.  It's a
feature we have worked on sufficiently that it should probably make it
into 2.0.4.  OK.  One of us

Re: syntax-local-binding

2012-01-23 Thread Mark H Weaver
Andy Wingo wi...@pobox.com writes:

 Your priorities are reversed from what they ought to be.

 What you _should_ be worried about is making commitments in our API that
 we must continue to support forever.  This is a _real_ problem, since it
 constrains our ability to modify our implementation in the future.

 I know I'm going to sound like Mr. Collins in Pride and Prejudice here,
 but I flatter myself that I know a thing or two about managing change --
 I mean, replacing the lazy-memoizing evaluator with the compiler,
 retrofitting psyntax into Guile, the whole subr mess, etc.

These are certainly impressive accomplishments, and I salute you for
this excellent work! :)

However, these accomplishments do not demonstrate that you understand
the importance of hiding implementation details so that future Guile
hackers can make similar transformations a decade or two from now.

For example, you seem unabashedly content to lock us into using psyntax
forever, despite the fact that it has known deficiencies having to do
with its phase story, as well as limitations in its handling of hygiene
in complex macros.  (c.f. Improved hygiene, SRFI 72).  I don't mean to
suggest that we should replace psyntax anytime soon, but we might want
to replace it in a decade or two.  Therefore, it concerns me when I see
internal psyntax representations exported in our API.

 But frankly though, regarding change, while we do need the freedom to
 modify some things, some other practical freedoms just don't make the
 cost/benefit cut, for me.

I agree that sometimes practical necessity outweighs the need to hide
implementation details.  However, in this case, the only benefit is to
satisfy your desire to keep `the-environment' out of psyntax.

 This conservatism is preventing Guile from adding features.  And we do
 need features -- local-eval and syntax-parse among them.

For the record, I absolutely want Stefan to have what he needs to
implement `syntax-parse'.  My understanding is that all he needs is a
way to associate properties with syntactic keywords.  Toward that end, I
proposed that we should add something analogous to procedure properties
for macros.  This can be done without exposing internal details as you
have done.

 But what if they're the wrong interface?

 Well, then we use the normal deprecation mechanism to get rid of them,
 eventually (in the 2.2 series, for example).  We learned something.
 Users get warned off the code.  Life goes on.

Yes, this is always an option, but it is a _painful_ option for all
involved.  If we can already foresee the need to deprecate an interface,
wouldn't it be better not to add it in the first place?

* * * * *

Anyway, I can plainly see that your mind is set on this, and that all of
the above words were a waste of effort, so I'm going to try to drop it.

I just have one final request: please at least change the lexical
environments in your `local-eval' implementation to use the future-proof
`evaluator procedure' representation, as I have done in mine.

FWIW, criticisms aside, I _do_ very much appreciate that you heard my
plea for local-eval in 2.0.4, and that you have put so much time into
this.  Thanks for that, and for all the wonderful things you have done
for Guile and GNU.

  Mark



Re: syntax-local-binding

2012-01-21 Thread Ludovic Courtès
Hi,

Mark H Weaver m...@netris.org skribis:

 Because it breaks your nice equivalence.  For example:

   (let ((x 1))
 (syntax-local-binding #'x))

 is not equivalent to:

   (let ((x 1))
 (local-eval '(syntax-local-binding #'x) (the-environment)))

 Put another way: if anyone uses `syntax-local-binding' to distinguish
 lexical variables from macros in some clever macro of theirs, this means
 that `local-eval' is now buggy with regard to their clever macro.

What about recommending against “clever macros” that use
‘syntax-local-binding’, or documenting the limitation in how
‘local-eval’ and ‘syntax-local-binding’ would interact?

After all, the point of ‘local-eval’ is to provide a compatibility later
with 1.8, and ‘syntax-local-binding’ didn’t exist there.

Thanks,
Ludo’.




Re: syntax-local-binding

2012-01-20 Thread Mark H Weaver
Andy Wingo wi...@pobox.com writes:
 `lexical'
   A lexically-bound variable.  The value is a unique token (in
   the sense of `eq?') identifying this binding.

 `macro'
   A syntax transformer, either local or global.  The value is
   the transformer procedure.

Ironically, `syntax-local-binding' renders the current simple
implementation strategy of `the-environment' inadequate, because
identifier-syntax is no longer sufficient to simulate a lexical.

More importantly, this exposing of internal binding representations will
interfere with our ability to change the representations later.

In particular, I was hoping to change the binding representation of
`syntax-rules' macros so that they are serializable.  In particular,
they would be represented by the `syntax-rules' form itself (the same
one that psyntax currently passes to `primitive-eval' to produce the
transformer procedure).  A weak-key hash table would cache the compiled
transformer procedures.

This would allow (the-environment) to capture locally-bound
`syntax-rules' macros.  Unfortunately, `syntax-local-binding', as
currently documented, now makes this impossible.

Thanks,
  Mark



Re: syntax-local-binding

2012-01-20 Thread Andy Wingo
On Fri 20 Jan 2012 21:26, Mark H Weaver m...@netris.org writes:

 Andy Wingo wi...@pobox.com writes:
 `lexical'
   A lexically-bound variable.  The value is a unique token (in
   the sense of `eq?') identifying this binding.

 `macro'
   A syntax transformer, either local or global.  The value is
   the transformer procedure.

 Ironically, `syntax-local-binding' renders the current simple
 implementation strategy of `the-environment' inadequate, because
 identifier-syntax is no longer sufficient to simulate a lexical.

Why do you say that?

 In particular, I was hoping to change the binding representation of
 `syntax-rules' macros so that they are serializable.  In particular,
 they would be represented by the `syntax-rules' form itself (the same
 one that psyntax currently passes to `primitive-eval' to produce the
 transformer procedure).  A weak-key hash table would cache the compiled
 transformer procedures.

 This would allow (the-environment) to capture locally-bound
 `syntax-rules' macros.  Unfortunately, `syntax-local-binding', as
 currently documented, now makes this impossible.

Why do you think that?  The procedures do carry metadata; I understood
that that was your strategy, to use the serialization of the
syntax-rules form in the procedure metadata.

Andy
-- 
http://wingolog.org/



Re: syntax-local-binding

2012-01-20 Thread Mark H Weaver
Andy Wingo wi...@pobox.com writes:

 On Fri 20 Jan 2012 21:26, Mark H Weaver m...@netris.org writes:

 Andy Wingo wi...@pobox.com writes:
 `lexical'
   A lexically-bound variable.  The value is a unique token (in
   the sense of `eq?') identifying this binding.

 `macro'
   A syntax transformer, either local or global.  The value is
   the transformer procedure.

 Ironically, `syntax-local-binding' renders the current simple
 implementation strategy of `the-environment' inadequate, because
 identifier-syntax is no longer sufficient to simulate a lexical.

 Why do you say that?

Because it breaks your nice equivalence.  For example:

  (let ((x 1))
(syntax-local-binding #'x))

is not equivalent to:

  (let ((x 1))
(local-eval '(syntax-local-binding #'x) (the-environment)))

Put another way: if anyone uses `syntax-local-binding' to distinguish
lexical variables from macros in some clever macro of theirs, this means
that `local-eval' is now buggy with regard to their clever macro.

 in particular, I was hoping to change the binding representation of
 `syntax-rules' macros so that they are serializable.  In particular,
 they would be represented by the `syntax-rules' form itself (the same
 one that psyntax currently passes to `primitive-eval' to produce the
 transformer procedure).  A weak-key hash table would cache the compiled
 transformer procedures.

 This would allow (the-environment) to capture locally-bound
 `syntax-rules' macros.  Unfortunately, `syntax-local-binding', as
 currently documented, now makes this impossible.

 Why do you think that?  The procedures do carry metadata; I understood
 that that was your strategy, to use the serialization of the
 syntax-rules form in the procedure metadata.

Well, this was in the context of a new strategy where psyntax would
include a new core form called `call-with-current-local-expander' that
calls its parameter (a procedure or macro) with a procedure that accepts
an expression and returns an expanded form.  In this case, the most
straightforward implementation would simply serialize the (r w mod)
structures directly.

Toward that end, I was thinking it would be nice to keep those
structures serializable.  The only part that's not currently
serializable are the transformer procedures for local macros.
Thus the change in representation.

More specifically: instead of attaching procedure properties/metadata to
the transformer procedures as is currently done, that information would
be put directly into the binding.  An alist would probably make the most
sense.  The source code of the macro (whatever's currently passed to
`primitive-eval') would also be included.

This may or may not be a good idea, I dunno.  I haven't fully thought it
through.  However, that's not the point.  The point is that by exposing
these details in the API, you are constraining our ability to make
changes of this kind.  I think that's very unfortunate.

 Mark



Re: local-eval on syntax-local-binding, bound-identifiers

2012-01-19 Thread Andy Wingo
On Tue 17 Jan 2012 00:27, Andy Wingo wi...@pobox.com writes:

 TBH I think this is the best thing we can do for local-eval.  We
 preserve flexibility for local-eval, make other experiments possible,
 and the local-eval implementation is a bit more perspicacious, as the
 scoping is more lexical (in the same file, even).

Perspicuous, rather.  How embarrassing!

Andy
-- 
http://wingolog.org/



Re: syntax-local-binding

2012-01-19 Thread Andy Wingo
Hello,

I have now pushed an implementation of syntax-local-binding to
stable-2.0, with the following documentation.  In the spirit of Eli's
note on Racket's syntax-local-value, it also works with identifiers that
are bound at the module level or the top level.  Comments and patches
welcome.

Cheers,

Andy

 -- Scheme Procedure: syntax-local-binding id
 Resolve the identifer ID, a syntax object, within the current
 lexical environment, and return two values, the binding type and a
 binding value.  The binding type is a symbol, which may be one of
 the following:

`lexical'
  A lexically-bound variable.  The value is a unique token (in
  the sense of `eq?') identifying this binding.

`macro'
  A syntax transformer, either local or global.  The value is
  the transformer procedure.

`pattern-variable'
  A pattern variable, bound via syntax-case.  The value is an
  opaque object, internal to the expander.

`displaced-lexical'
  A lexical variable that has gone out of scope.  This can
  happen if a badly-written procedural macro saves a syntax
  object, then attempts to introduce it in a context in which
  it is unbound.  The value is `#f'.

`global'
  A global binding.  The value is a pair, whose head is the
  symbol, and whose tail is the name of the module in which to
  resolve the symbol.

`other'
  Some other binding, like `lambda' or other core bindings.  The
  value is `#f'.

 This is a very low-level procedure, with limited uses.  One case in
 which it is useful is to build abstractions that associate
 auxiliary information with macros:

  (define aux-property (make-object-property))
  (define-syntax-rule (with-aux aux value)
(let ((trans value))
  (set! (aux-property trans) aux)
  trans)))
  (define-syntax retrieve-aux
(lambda (x)
  (syntax-case x ()
((x id)
 (call-with-values (lambda () (syntax-local-binding #'id))
   (lambda (type val)
 (with-syntax ((aux (datum-syntax #'here
   (and (eq? type 'macro)
(aux-property 
val)
   #''aux)))
  (define-syntax foo
(with-aux 'bar
  (syntax-rules () ((_) 'foo
  (foo)
  = foo
  (retrieve-aux foo)
  = bar

 `syntax-local-binding' must be called within the dynamic extent of
 a syntax transformer; to call it otherwise will signal an error.

-- 
http://wingolog.org/



Re: local-eval on syntax-local-binding, bound-identifiers

2012-01-17 Thread David Kastrup
Andy Wingo wi...@pobox.com writes:

 What if instead we implemented closure serialization somehow?  Then we
 would handle procedural macros too, and bound-identifiers would still be
 sufficient.

 Maybe that idea is a little too crazy.

Are we still talking about Scheme?  The language with
call-with-current-continuation?  a little too crazy is not a
criterion.  Too complex to work or or with would be.  Those are
related, but not necessarily the same.

-- 
David Kastrup




Re: local-eval on syntax-local-binding, bound-identifiers

2012-01-16 Thread Mark H Weaver
Hi Andy!

Andy Wingo wi...@pobox.com writes:
 + (cons (wrap (car symnames)
 + (anti-mark (make-wrap (car marks) subst))

 * Why are you adding anti-marks here?

 As the changelog noted (and a comment should have noted ;), the
 identifiers are anti-marked so that syntax transformers can introduce
 them, as-is.

 The purpose of this procedure is to get a list of identifiers, and to
 capture some subset of them.  It will do so by introducing references to
 them in the expansion of some macro.  However they are not introduced
 identifiers: they come from the code itself.  They are input the macro,
 and as such need an anti-mark.

 The anti-mark will be stripped from the expansion when the transformer
 that called `bound-identifiers' returns.

Does this mean that `bound-identifiers' will not function properly when
used outside of a macro?  What about if it's used within a macro that
was generated by another macro (or things of that nature)?  Are there
cases where you might need to strip more than one anti-mark?

To use your phrase, this has a bad smell.

 More importantly: I notice that you are not stripping the psyntax wrap
 from identifiers placed within the wrapper procedure above.  There are
 certainly benefits to that, but remember that the wrapper procedure will
 in general be serialized to disk and evaluated in a different Guile
 session, where the gensym counters have been reset.

 Of course, like all macros!  The forgeable gensym issue is something we
 have in Guile, more generally, that needs a broader solution.

Ah, good point!  Macros already serialize syntax-objects to disk.
psyntax wraps are already part of our ABI, so nothing new there.

However, I fear that the gensym issue might be a serious problem for
`local-eval', even though it hasn't been a problem for macros.

The reason it has not been a problem with macros is that, within a
top-level macro (which are the only ones used across Guile sessions),
the only syntax-objects that can be meaningfully _introduced_ into the
expansion are top-level/module bindings.  But these bindings have no
associated labels or gensyms, because they're not in the wrap.

On the other hand, with `local-eval', it seems to me quite plausible
that gensym collisions might occur.  Suppose in one Guile session you
compile a procedure (foo) that uses (the-environment), and then in
another Guile session, you call (foo) and then `local-eval' with the
environment returned by (foo).  Now the wrapper procedure splices
together syntax objects from two different Guile sessions into a single
top-level form, where (unlike in the macro case) all of these syntax
objects are lexicals, and thus depend on the gensyms and the labels.

See how this is a problem now where it wasn't before?
Or am I missing something?

 +((module? e)
 + ;; Here we evaluate the expression within `lambda', and then
 + ;; call the resulting procedure outside of the dynamic extent
 + ;; of `eval'.  We do this because `eval' sets (current-module)
 + ;; within its dynamic extent, and we don't want that.  Also,
 + ;; doing it this way makes this a proper tail call.
 + ((eval #`(lambda () #,x) e)))

 * This was my mistake, but since I'm already marking up the code:
 the `lambda' wrap above needs a `#f' before `e' to force expression
 context.

 OK.  (Note though that (eval X e) does indeed evaluate X in tail
 position.)

Looks to me like `eval' is initially bound to the C function scm_eval.
Is it later rebound to a Scheme procedure?  If so, where?

 For the record, I still think it's better for `the-environment' to be
 implemented within psyntax as a core form.  It's a fundamental syntactic
 construct with clean semantics, and it belongs in psyntax with its
 brethren.  Your desire to remove it from psyntax has caused you to add
 far less elegant interfaces that have been hastily designed, and that
 may not even be sufficient for a full implementation of
 `the-environment' that captures mutually-recursive local macros.

 In pursuit of the goal of agreeing on a strategy, I would like to
 convince you that you are wrong on all of these points :)  So, in that
 spirit, I argue:

Very well, I will endeavor to be open-minded.

 `the-environment' is not fundamental: it can be implemented in terms of
 simpler primitives.

The same can be said of `lambda' or `syntax-case', but that's not the
appropriate way to choose primitives in a language.  The set of
primitives chosen in Scheme are not the ones that are simplest to
implement.  It makes more sense to choose primitives with simple, clean
semantics, which segues nicely into your next paragraph.

 `the-environment' does not have clean semantics, inasmuch as it has
 nothing worthy of the name, not yet anyway.  The lambda calculus, the
 scheme language, even the syntax-case system have well-studied semantics
 (denotational and/or operational), and lots of 

Re: local-eval on syntax-local-binding, bound-identifiers

2012-01-16 Thread Mark H Weaver
Hi Andy!

Thanks again for working on this.

Andy Wingo wi...@pobox.com writes:
 * Why are you adding anti-marks here?

 As the changelog noted (and a comment should have noted ;), the
 identifiers are anti-marked so that syntax transformers can introduce
 them, as-is.

 The purpose of this procedure is to get a list of identifiers, and to
 capture some subset of them.  It will do so by introducing references to
 them in the expansion of some macro.  However they are not introduced
 identifiers: they come from the code itself.  They are input the macro,
 and as such need an anti-mark.

 The anti-mark will be stripped from the expansion when the transformer
 that called `bound-identifiers' returns.

 Does this mean that `bound-identifiers' will not function properly when
 used outside of a macro?  What about if it's used within a macro that
 was generated by another macro (or things of that nature)?  Are there
 cases where you might need to strip more than one anti-mark?

 Well, bound-identifiers is a procedure, so if you are using it outside
 the dynamic extent of a transformer procedure, that means that you have
 a syntax object that you squirreled away from somewhere, so already
 we're in somewhat uncharted territory.

How about something like (bound-identifiers #'here)?
or (bound-identifiers #'x) where `x' is some lexical variable?

 Macro-generating macros should be fine, here.  `expand-macro' is
 iterative, not recursive, so you don't need to strip anti-marks twice.

Ah, okay.  Good point!

 I agree that this anti-mark has a bad smell, but the idea of a
 `bound-identifiers' procedure or form sounds like a good idea, so if you
 have any suggestions for improvement here, they are most welcome.

As I've already said, I don't think `bound-identifiers' will be useful
in a full implementation of `local-eval', so once we move to that
improved implementation, `bound-identifiers' will be left around as an
orphan: a primitive of dubious value, introduced specifically to
implement something that it turned out to be insufficient for.

If you insist on this strategy, I think what we really need is a list of
ribs, where each rib also specifies whether it is recursive.  We don't
actually care about `let' vs `letrec' (though there's no harm in
providing that information in the interface, and it probably makes sense
to for consistency), but we _do_ care about the difference between
`let-syntax', `letrec-syntax', and internal bodies with
mutually-recursive `define-syntax' forms.

See how we're exposing increasingly complex internal psyntax structures
in order to achieve your dream of making `local-eval' sleep outside in
the shed?

 [W]ith `local-eval', it seems to me quite plausible that gensym
 collisions might occur.  Suppose in one Guile session you compile a
 procedure (foo) that uses (the-environment), and then in another Guile
 session, you call (foo) and then `local-eval' with the environment
 returned by (foo).  Now the wrapper procedure splices together syntax
 objects from two different Guile sessions into a single top-level
 form, where (unlike in the macro case) all of these syntax objects are
 lexicals, and thus depend on the gensyms and the labels.

 See how this is a problem now where it wasn't before?
 Or am I missing something?

 To be perfectly honest, this stuff is very confusing to me, but I think
 I can see how this can happen, yes.

 I do think that it's important to fix this bug at some point, but IMO it
 is not a blocker for local-eval, much less 2.0.4.

I strongly disagree.  Your implementation will clearly be buggy without
a proper solution to the collision of gensyms (labels and marks, at
least).  I don't know about you, but personally I prefer rock-solid code
with clearly documented limitations (that almost no one is likely to hit
anyway) to buggy code.

If you don't want to deal with the gensym problem for 2.0.4, there's an
easy solution.  Simply strip the wraps for now (as is done by my patch),
and everything will robust as long as we don't capture local syntax.

 BTW, did you see my most recent model for thinking about `local-eval'?

 (the-environment) expands to (list (lambda () expr) ...), with one
 element for every possible expression: a countably infinite list that
 could be built lazily.  `local-eval' simply chooses the appropriate
 procedure from the list and calls it.  A poor implementation strategy,
 but the semantic meaning is quite clear, no?

 It sounds clear, but does it have any explanatory power?  It sounds like
 it could apply just as well to any other computation...

I don't understand what you mean here.  It seems to me that this model
can answer any question you could possibly have about the observable
behaviors of `the-environment' and `local-eval', besides their
efficiency.  Can you provide a counter-example to this claim?

 Creating wraps is not the hack.  It's creating wraps that are scoped in
 another specific module.  With the-environment in psyntax, psyntax
 

Re: local-eval on syntax-local-binding, bound-identifiers

2012-01-16 Thread Andy Wingo
Hi Mark,

On Mon 16 Jan 2012 21:36, Mark H Weaver m...@netris.org writes:

 Thanks again for working on this.

And thank you again for all your work, and patience with my
pigheadedness.

 if you insist in this foolish quest to banish `the-environment' to
 sleep in the shed as a second-class citizen, I cannot stop you :)

TBH I think this is the best thing we can do for local-eval.  We
preserve flexibility for local-eval, make other experiments possible,
and the local-eval implementation is a bit more perspicacious, as the
scoping is more lexical (in the same file, even).

I know there's a smilie in your statement, but really, it's not just
local-eval:  there's loads more that should be broken out into modules
over time, somehow :)  Think of it as building a hippie commune of
functionality, instead of making everyone live in the same house :)
(OK, that's stretching it a bit, but perhaps it is partially apt?)

Now, specific commentary.

 How about something like (bound-identifiers #'here)?

scheme@(guile-user) (bound-identifiers #'here)
$5 = ()

scheme@(guile-user) (let ((x 10)) (bound-identifiers #'here))
$6 = (#(syntax-object x ((#f top) shift #(ribcage #(x) #((top)) #(i176))) 
(hygiene guile-user)))

What should the answer be in this case?  Would you expect `x' in the
list?  Certainly for the-environment you would.  But here:

scheme@(guile-user) (define-syntax bound-here
   (lambda (x)
 (with-syntax (((id ...)
(map (lambda (id) (datum-syntax x id))
 (bound-identifiers #'here
   #'(list 'id ...
scheme@(guile-user) bound-here
$7 = (#(syntax-object x ((#f top) shift #(ribcage #(x) #((top)) #(i192))) 
(hygiene guile-user)))
scheme@(guile-user) (let ((y 10)) bound-here)
$8 = (#(syntax-object x ((#f top) shift #(ribcage #(x) #((top)) #(i192))) 
(hygiene guile-user)))

So, it seems to be sensible.

Now, what to do with these identifiers: you if you introduce one into
another macro, the mark will indeed be stripped.  I'm not sure what else
you can do with a syntax-object, actually!  Pass it directly to eval or
compile, I guess, and in that case we do lose, as the anti-mark isn't
stripped.  But that's the case for other syntax objects captured in a
syntax transformer, as well.

Should we anti-mark only within the dynamic extent of a transformer, I
wonder?

 As I've already said, I don't think `bound-identifiers' will be useful
 in a full implementation of `local-eval', so once we move to that
 improved implementation, `bound-identifiers' will be left around as an
 orphan: a primitive of dubious value, introduced specifically to
 implement something that it turned out to be insufficient for.

Hum.  Definitely something to think about.

What if instead we implemented closure serialization somehow?  Then we
would handle procedural macros too, and bound-identifiers would still be
sufficient.

Maybe that idea is a little too crazy.

If we have to lexical contours associated with bindings, recursive is
only one bit: you probably also need letrec vs letrec*.

 To be perfectly honest, this stuff is very confusing to me, but I think
 I can see how this can happen, yes.

 I do think that it's important to fix this bug at some point, but IMO it
 is not a blocker for local-eval, much less 2.0.4.

 I strongly disagree.  Your implementation will clearly be buggy without
 a proper solution to the collision of gensyms (labels and marks, at
 least).  I don't know about you, but personally I prefer rock-solid code
 with clearly documented limitations (that almost no one is likely to hit
 anyway) to buggy code.

 If you don't want to deal with the gensym problem for 2.0.4, there's an
 easy solution.  Simply strip the wraps for now (as is done by my patch),
 and everything will robust as long as we don't capture local syntax.

Thinking about it a little more, labels are a non-issue.  All they need
to be is unique in the sense of eq?.  Labels are strings.  If they are
loaded in separate compilation units, they will be unique, no matter
what their contents.

Labels are more important than marks, also, for the correctness of the
algorithm.  A mark collision is only an issue if there is also a
symbolic collision.  Label collision could alias completely unrelated
bindings.

Anyway, I would rather serialize bad marks than no marks.  That's my
personal opinion ;-) But if you think this is a huge issue, let's fix
the marks to be more unique, no?

Note that there is a well-known optimization that you don't actually
need to generate the characters corresponding to a gensym until they are
needed.  It might serve your purposes.

OK, I'm getting very sleepy now :)  Let me know your thoughts.  It would
be great if all of this could land before Sunday.  Though the cricket
folk say pace is nothing without guile, Guile is nothing without a
good development pace ;-)

Cheers,

Andy
-- 

syntax-local-binding

2012-01-15 Thread Andy Wingo
Hi list,

Attached is a patch that implements a new accessor,
syntax-local-binding.  It's like syntax-local-value, but can also
determine if an identifier is a pattern var or a normal lexical.

   (define-syntax local-binding
  (lambda (x)
(syntax-case x ()
  ((_ id) (identifier? #'id)
   (call-with-values (lambda () (syntax-local-binding #'id))
 (lambda (x y)
   (with-syntax ((type (datum-syntax #'here x)))
 #''type)))
   (let-syntax ((x (lambda (x) 10))) (local-binding x))
  $3 = local-macro
   (syntax-case #'(foo) () ((id) (local-binding id)))
  $4 = pattern-variable
   (let ((x 10)) (local-binding x))
  $5 = lexical

It returns two values.  The first is a symbol, either `local-macro',
`lexical', or `pattern-variable'.  The second is specific to the type.
For local-macro it is the transformer binding.  For lexical it is the
gensym name of the lexical.  For pattern variables, it is something
opaque that identifies that pattern var.

Inspired by a patch by Stefan Israelsson Tampe.

I'm going to try to implement the-environment with this.  We'll see how
it goes!

Andy
-- 
http://wingolog.org/



Re: syntax-local-binding

2012-01-15 Thread Andy Wingo
On Sun 15 Jan 2012 18:00, Andy Wingo wi...@pobox.com writes:

 Attached is a patch that implements a new accessor,
 syntax-local-binding.

Here 'tis!

From 09ba44abeb47cdf4ec61df6f7386217f0cbe30c7 Mon Sep 17 00:00:00 2001
From: Andy Wingo wi...@pobox.com
Date: Sun, 15 Jan 2012 17:51:02 +0100
Subject: [PATCH] add syntax-local-binding

* module/ice-9/boot-9.scm (syntax-local-binding): New binding.

* module/ice-9/psyntax.scm: Locally define a fluid that holds the
  transformer environment.  with-transformer-environment calls a
  procedure with the transformer environment, or raises an error if
  called outside the extent of a transformer.  Bind
  transformer-environment in expand-macro.
  (syntax-local-binding): New procedure to return binding information of
  a lexially bound identifier (a lexical, local macro, or pattern
  variable).
---
 module/ice-9/boot-9.scm  |1 +
 module/ice-9/psyntax.scm |   39 +--
 2 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/module/ice-9/boot-9.scm b/module/ice-9/boot-9.scm
index f661d08..9cdd8d1 100644
--- a/module/ice-9/boot-9.scm
+++ b/module/ice-9/boot-9.scm
@@ -389,6 +389,7 @@ If there is no handler at all, Guile prints an error and then exits.
 (define generate-temporaries #f)
 (define bound-identifier=? #f)
 (define free-identifier=? #f)
+(define syntax-local-binding #f)
 
 ;; $sc-dispatch is an implementation detail of psyntax. It is used by
 ;; expanded macros, to dispatch an input against a set of patterns.
diff --git a/module/ice-9/psyntax.scm b/module/ice-9/psyntax.scm
index 1bf3c32..dcabafe 100644
--- a/module/ice-9/psyntax.scm
+++ b/module/ice-9/psyntax.scm
@@ -786,6 +786,14 @@
   id))
  (else (syntax-violation 'id-var-name invalid id id)
 
+(define transformer-environment
+  (make-fluid
+   (lambda (k)
+ (error called outside the dynamic extent of a syntax transformer
+
+(define (with-transformer-environment k)
+  ((fluid-ref transformer-environment) k))
+
 ;; free-id=? must be passed fully wrapped ids since (free-id=? x y)
 ;; may be true even if (free-id=? (wrap x w) (wrap y w)) is not.
 
@@ -1321,8 +1329,10 @@
(syntax-violation #f encountered raw symbol in macro output
  (source-wrap e w (wrap-subst w) mod) x))
   (else (decorate-source x s)
-(rebuild-macro-output (p (source-wrap e (anti-mark w) s mod))
-  (new-mark
+(with-fluids ((transformer-environment
+   (lambda (k) (k e r w s rib mod
+  (rebuild-macro-output (p (source-wrap e (anti-mark w) s mod))
+(new-mark)
 
 (define expand-body
   ;; In processing the forms of the body, we create a new, empty wrap.
@@ -2435,6 +2445,31 @@
 (set! syntax-source
   (lambda (x) (source-annotation x)))
 
+(set! syntax-local-binding
+  (lambda (id)
+(arg-check nonsymbol-id? id 'syntax-local-value)
+(with-transformer-environment
+ (lambda (e r w s rib mod)
+   (define (strip-anti-mark w)
+ (let ((ms (wrap-marks w)) (s (wrap-subst w)))
+   (if (and (pair? ms) (eq? (car ms) the-anti-mark))
+   ;; output is from original text
+   (make-wrap (cdr ms) (if rib (cons rib (cdr s)) (cdr s)))
+   ;; output introduced by macro
+   (error what!!!
+   (let ((label (id-var-name (syntax-object-expression id)
+ (strip-anti-mark (syntax-object-wrap id)
+ (if (not (string? label))
+ (error identifier not lexically bound id))
+ (let ((b (assq-ref r label)))
+   (if (not b)
+   (error displaced lexical id))
+   (case (binding-type b)
+ ((lexical) (values 'lexical (binding-value b)))
+ ((macro) (values 'local-macro (binding-value b)))
+ ((syntax) (values 'pattern-variable (binding-value b)))
+ (else (error unpossible! b)
+
 (set! generate-temporaries
   (lambda (ls)
 (arg-check list? ls 'generate-temporaries)
-- 
1.7.8.3


-- 
http://wingolog.org/


local-eval on syntax-local-binding, bound-identifiers

2012-01-15 Thread Andy Wingo
Hi Mark,

I had made some noise about preferring an implementation of local-eval
based on primitives from psyntax.  But, I didn't clarify my argument by
providing the primitives.  Here are some patches that provide
syntax-local-binding, as I noted in my previous mail, and also a
procedure to get all identifiers that are visible within the scope of
another identifier.

I then refactored your patch to implement local-eval entirely in terms
of these primitives and other normal macrology.  What do you think?  In
the interests of time and debugging, I removed the support for pattern
variables; it should be easy to add back.

These are preliminary patches, but if this approach proves to be viable,
I would prefer it to one that bakes the-environment into psyntax.

WDYT?

Regards,

Andy

From 48d8e52e316984f2bf9380df85079bb5fa142253 Mon Sep 17 00:00:00 2001
From: Andy Wingo wi...@pobox.com
Date: Sun, 15 Jan 2012 17:51:02 +0100
Subject: [PATCH 1/3] add syntax-local-binding

* module/ice-9/boot-9.scm (syntax-local-binding): New binding.

* module/ice-9/psyntax.scm: Locally define a fluid that holds the
  transformer environment.  with-transformer-environment calls a
  procedure with the transformer environment, or raises an error if
  called outside the extent of a transformer.  Bind
  transformer-environment in expand-macro.
  (syntax-local-binding): New procedure to return binding information of
  a lexically bound identifier (a lexical, local macro, a pattern
  variable, or a displaced lexical).
---
 module/ice-9/boot-9.scm  |1 +
 module/ice-9/psyntax.scm |   39 +--
 2 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/module/ice-9/boot-9.scm b/module/ice-9/boot-9.scm
index f661d08..9cdd8d1 100644
--- a/module/ice-9/boot-9.scm
+++ b/module/ice-9/boot-9.scm
@@ -389,6 +389,7 @@ If there is no handler at all, Guile prints an error and then exits.
 (define generate-temporaries #f)
 (define bound-identifier=? #f)
 (define free-identifier=? #f)
+(define syntax-local-binding #f)
 
 ;; $sc-dispatch is an implementation detail of psyntax. It is used by
 ;; expanded macros, to dispatch an input against a set of patterns.
diff --git a/module/ice-9/psyntax.scm b/module/ice-9/psyntax.scm
index 1bf3c32..30685bc 100644
--- a/module/ice-9/psyntax.scm
+++ b/module/ice-9/psyntax.scm
@@ -786,6 +786,14 @@
   id))
  (else (syntax-violation 'id-var-name invalid id id)
 
+(define transformer-environment
+  (make-fluid
+   (lambda (k)
+ (error called outside the dynamic extent of a syntax transformer
+
+(define (with-transformer-environment k)
+  ((fluid-ref transformer-environment) k))
+
 ;; free-id=? must be passed fully wrapped ids since (free-id=? x y)
 ;; may be true even if (free-id=? (wrap x w) (wrap y w)) is not.
 
@@ -1321,8 +1329,10 @@
(syntax-violation #f encountered raw symbol in macro output
  (source-wrap e w (wrap-subst w) mod) x))
   (else (decorate-source x s)
-(rebuild-macro-output (p (source-wrap e (anti-mark w) s mod))
-  (new-mark
+(with-fluids ((transformer-environment
+   (lambda (k) (k e r w s rib mod
+  (rebuild-macro-output (p (source-wrap e (anti-mark w) s mod))
+(new-mark)
 
 (define expand-body
   ;; In processing the forms of the body, we create a new, empty wrap.
@@ -2435,6 +2445,31 @@
 (set! syntax-source
   (lambda (x) (source-annotation x)))
 
+(set! syntax-local-binding
+  (lambda (id)
+(arg-check nonsymbol-id? id 'syntax-local-value)
+(with-transformer-environment
+ (lambda (e r w s rib mod)
+   (define (strip-anti-mark w)
+ (let ((ms (wrap-marks w)) (s (wrap-subst w)))
+   (if (and (pair? ms) (eq? (car ms) the-anti-mark))
+   ;; output is from original text
+   (make-wrap (cdr ms) (if rib (cons rib (cdr s)) (cdr s)))
+   ;; output introduced by macro
+   (make-wrap ms (if rib (cons rib s) s)
+   (let ((label (id-var-name (syntax-object-expression id)
+ (strip-anti-mark (syntax-object-wrap id)
+ (if (not (string? label))
+ (error identifier not lexically bound id))
+ (let ((b (assq-ref r label)))
+   (if b
+   (case (binding-type b)
+ ((lexical) (values 'lexical (binding-value b)))
+ ((macro) (values 'local-macro (binding-value b)))
+ ((syntax) (values 'pattern-variable (binding-value b)))
+ (else (error unpossible! b)))
+   (values

Re: local-eval on syntax-local-binding, bound-identifiers

2012-01-15 Thread Mark H Weaver
Hi Andy,

Thanks very much for heeding my call for `local-eval' in 2.0.4, and
for putting so much time into this.

For the record, I still think it's better for `the-environment' to be
implemented within psyntax as a core form.  It's a fundamental syntactic
construct with clean semantics, and it belongs in psyntax with its
brethren.  Your desire to remove it from psyntax has caused you to add
far less elegant interfaces that have been hastily designed, and that
may not even be sufficient for a full implementation of
`the-environment' that captures mutually-recursive local macros.

That said, there's a lot to like in your implementation, and it has some
notable improvements over mine.  It also has some problems, not all of
which are trivial.

Please see below, where I have inserted specific questions and comments
into your patch.

  Thanks again,
  Mark


[... skipped the first patch, which looks very well implemented, though
 I'm still not sure that we should be exposing this in our API ...]

 From 2c3da44320019453115811af386febaa7eb241c3 Mon Sep 17 00:00:00 2001
 From: Andy Wingo wi...@pobox.com
 Date: Sun, 15 Jan 2012 18:39:44 +0100
 Subject: [PATCH 2/3] add bound-identifiers

 * module/ice-9/boot-9.scm (bound-identifiers): Declare variable.
 * module/ice-9/psyntax.scm: Add all-bound-identifiers helper, and define
   bound-identifiers.  The identifiers are anti-marked so that syntax
   transformers can introduce them, as-is.
 ---
  module/ice-9/boot-9.scm  |1 +
  module/ice-9/psyntax.scm |   49 
 ++
  2 files changed, 50 insertions(+), 0 deletions(-)

 diff --git a/module/ice-9/boot-9.scm b/module/ice-9/boot-9.scm
 index 9cdd8d1..b8aa842 100644
 --- a/module/ice-9/boot-9.scm
 +++ b/module/ice-9/boot-9.scm
 @@ -389,6 +389,7 @@ If there is no handler at all, Guile prints an error and 
 then exits.
  (define generate-temporaries #f)
  (define bound-identifier=? #f)
  (define free-identifier=? #f)
 +(define bound-identifiers #f)
  (define syntax-local-binding #f)
  
  ;; $sc-dispatch is an implementation detail of psyntax. It is used by
 diff --git a/module/ice-9/psyntax.scm b/module/ice-9/psyntax.scm
 index 30685bc..25543e0 100644
 --- a/module/ice-9/psyntax.scm
 +++ b/module/ice-9/psyntax.scm
 @@ -786,6 +786,48 @@
id))
   (else (syntax-violation 'id-var-name invalid id id)
  
 +;;
 +;; all-bound-identifiers returns a list of all lexically bound
 +;; identifiers, as syntax objects.  They are in order from outer to
 +;; inner.
 +;;
 +(define all-bound-identifiers
 +  (lambda (w mod)
 +(define scan
 +  (lambda (subst results)
 +(if (null? subst)
 +results
 +(let ((fst (car subst)))
 +  (if (eq? fst 'shift)
 +  (scan (cdr subst) results)
 +  (let ((symnames (ribcage-symnames fst))
 +(marks (ribcage-marks fst)))
 +(if (vector? symnames)
 +(scan-vector-rib subst symnames marks results)
 +(scan-list-rib subst symnames marks 
 results
 +(define scan-list-rib
 +  (lambda (subst symnames marks results)
 +(let f ((symnames symnames) (marks marks) (results results))
 +  (if (null? symnames)
 +  (scan (cdr subst) results)
 +  (f (cdr symnames) (cdr marks)
 + (cons (wrap (car symnames)
 + (anti-mark (make-wrap (car marks) subst))

* Why are you adding anti-marks here?

 + mod)
 +   results))
 +(define scan-vector-rib
 +  (lambda (subst symnames marks results)
 +(let ((n (vector-length symnames)))
 +  (let f ((i 0) (results results))
 +(if (fx= i n)
 +(scan (cdr subst) results)
 +(f (fx+ i 1)
 +   (cons (wrap (vector-ref symnames i)
 +   (anti-mark (make-wrap (vector-ref marks 
 i) subst))

* Ditto.

 +   mod)
 + results)))
 +(scan (wrap-subst w) '(
 +
  (define transformer-environment
(make-fluid
 (lambda (k)
 @@ -2470,6 +2512,13 @@
   (else (error unpossible! b)))
 (values 'displaced-lexical #f
  
 +(set! bound-identifiers
 +  (lambda (x)
 +(arg-check nonsymbol-id? x 'bound-identifiers)
 +(reverse
 + (all-bound-identifiers (syntax-object-wrap x)
 +(syntax-object-module x)
 +
  (set! generate-temporaries
(lambda (ls)
  (arg-check list? ls 'generate-temporaries