Re: Precedence for reader extensions

2013-02-19 Thread Mikael Djurfeldt
On Tue, Feb 19, 2013 at 12:33 AM, Mark H Weaver m...@netris.org wrote:
 Mikael Djurfeldt mik...@djurfeldt.com writes:
 I propose to simplify this to only two levels:

 1. %read-hash-procedures
 2. predefined syntax

It turns out that the change I propose above was already implemented
in read.c.  The effect just wasn't visible due to a bug in flush_ws
which caused all #! to be erroneously removed if they exist as the
outermost expression.

In the attached diff, I've fixed the flush_ws bug and cleaned up some
garbage code in scm_read_sharp which was unreachable.

Can I push this into the repository?

 I don't think this would be sufficient.  The problem is that tokens of
 the form #!symboldelimiter have become standardized.  To name a
 few examples, both R6RS and R7RS define the reader directives
 #!fold-case and #!no-fold-case, R6RS has #!r6rs, and SRFI-105 has
 #!curly-infix.  Guile also has #! ... !# block comments to help with the
 handling of executable scripts.

In what sense is it not sufficient?  In any case: The present diff
doesn't remove any functionality or make performance worse.  It only
removes some inconsistent behavior.  At the same time it allows
support for mit-scheme #!optional and #!rest.

Best regards,
Mikael D.


reader-fix.diff
Description: Binary data


Re: [Guile-commits] GNU Guile branch, wip-rtl-cps, updated. v2.1.0-180-g0d0808a

2013-02-19 Thread Noah Lavine
Hello,

Yes, I completely agree with this. I didn't do that immediately because I'm
trying to get the infrastructure for the general case working. I plan to
implement un-boxing in CPS. The real reason not to do it yet is that the
tree-il-CPS compiler can't compile any examples that would actually need
boxes. (But it will be able to soon!)

Noah


On Tue, Feb 19, 2013 at 12:53 AM, Mark H Weaver m...@netris.org wrote:

 Hi Noah,

 Noah Lavine noah.b.lav...@gmail.com writes:
  commit 0d0808ae3f7390ffb250b9deb6706ad4158cce0e
  Author: Noah Lavine noah.b.lav...@gmail.com
  Date:   Mon Feb 18 14:10:58 2013 -0500
 
  Make Lambda Arguments Mutable
 
  * module/language/cps.scm: let variable objects come with an
initialization value.
  * module/language/tree-il/compile-cps.scm: put all lambda arguments
 in
variable boxes, so they are mutable.

 Lambda arguments (and all other lexical variables) should only be put
 into boxes if they are 'set!' somewhere within their lexical scope.
 This can always be determined at compile time.  It is crucial that we
 minimize the number of mutable variables, since they inhibit most
 optimizations.

 The required analysis is already implemented in tree-il/analyze.scm.

  Regards,
Mark



Re: [Guile-commits] GNU Guile branch, wip-rtl-cps, updated. v2.1.0-180-g0d0808a

2013-02-19 Thread Noah Lavine
Oh, and thanks a lot for reviewing the CPS stuff! I really appreciate it,
and I think it will make the end result a lot better than whatever I could
do on my own.

Noah


On Tue, Feb 19, 2013 at 9:28 AM, Noah Lavine noah.b.lav...@gmail.comwrote:

 Hello,

 Yes, I completely agree with this. I didn't do that immediately because
 I'm trying to get the infrastructure for the general case working. I plan
 to implement un-boxing in CPS. The real reason not to do it yet is that the
 tree-il-CPS compiler can't compile any examples that would actually need
 boxes. (But it will be able to soon!)

 Noah


 On Tue, Feb 19, 2013 at 12:53 AM, Mark H Weaver m...@netris.org wrote:

 Hi Noah,

 Noah Lavine noah.b.lav...@gmail.com writes:
  commit 0d0808ae3f7390ffb250b9deb6706ad4158cce0e
  Author: Noah Lavine noah.b.lav...@gmail.com
  Date:   Mon Feb 18 14:10:58 2013 -0500
 
  Make Lambda Arguments Mutable
 
  * module/language/cps.scm: let variable objects come with an
initialization value.
  * module/language/tree-il/compile-cps.scm: put all lambda arguments
 in
variable boxes, so they are mutable.

 Lambda arguments (and all other lexical variables) should only be put
 into boxes if they are 'set!' somewhere within their lexical scope.
 This can always be determined at compile time.  It is crucial that we
 minimize the number of mutable variables, since they inhibit most
 optimizations.

 The required analysis is already implemented in tree-il/analyze.scm.

  Regards,
Mark





Re: Precedence for reader extensions

2013-02-19 Thread Mark H Weaver
Mikael Djurfeldt mik...@djurfeldt.com writes:
 On Tue, Feb 19, 2013 at 12:33 AM, Mark H Weaver m...@netris.org wrote:
 Mikael Djurfeldt mik...@djurfeldt.com writes:
 I propose to simplify this to only two levels:

 1. %read-hash-procedures
 2. predefined syntax

 It turns out that the change I propose above was already implemented
 in read.c.  The effect just wasn't visible due to a bug in flush_ws
 which caused all #! to be erroneously removed if they exist as the
 outermost expression.

I'm not sure that I consider this a bug.  All of the tokens that
flush_ws removes can appear anywhere that whitespace is allowed, and are
considered whitespace to the caller (although reader directives may
modify the per-port reader options as a side-effect).

  #;expr (sexp-comments)
  #!fold-case  (reader directives)
  #! ... !#(shebang block comments)
  #| ... |#(r6rs block comments)

 In the attached diff, I've fixed the flush_ws bug and cleaned up some
 garbage code in scm_read_sharp which was unreachable.

 Can I push this into the repository?

I'm uncomfortable with globally overriding standard read syntax.  In a
large scheme system such as Guile, there are many modules that use
'read' and expect it to act in accordance with standard lexical
conventions.

Therefore, I'd prefer to limit 'read-hash-extend' to adding new syntax
that would otherwise have been considered an error.  If you're going to
override standard read syntax, then I think it should only be done on a
per-port basis.

Therefore, I'd prefer a precedence closer to this:

  1. (possibly) per-port variant of %read-hash-procedures
  2. predefined syntax
  3. %read-hash-procedures

 I don't think this would be sufficient.  The problem is that tokens of
 the form #!symboldelimiter have become standardized.  To name a
 few examples, both R6RS and R7RS define the reader directives
 #!fold-case and #!no-fold-case, R6RS has #!r6rs, and SRFI-105 has
 #!curly-infix.  Guile also has #! ... !# block comments to help with the
 handling of executable scripts.

 In what sense is it not sufficient?  In any case: The present diff
 doesn't remove any functionality or make performance worse.  It only
 removes some inconsistent behavior.  At the same time it allows
 support for mit-scheme #!optional and #!rest.

The problem with this approach is that it does not compose.  You want to
add #!optional and #!rest.  R6RS added #!r6rs, #!fold-case, and
#!no-fold-case.  SRFI-105 added #!curly-infix.  But there can be only
one read-hash-procedure for #!, and it's global to the entire system.

That's why I suggested a way to add new tokens of the form
#!symboldelimiter.  That way, you could add handlers for #!rest
and #!optional without interfering with the other #!symboldelimiter
tokens.

What do you think?

Regards,
  Mark



Re: CPS Update

2013-02-19 Thread Noah Lavine
Hello,

On Sat, Feb 16, 2013 at 4:18 PM, Mark H Weaver m...@netris.org wrote:

 Hi Noah,

  On Sat, Feb 16, 2013 at 2:14 PM, Mark H Weaver m...@netris.org wrote:
 [...]
  Noah Lavine noah.b.lav...@gmail.com writes:
 
  You mean if a function modifies another function that called it.

 There are many other cases.  Think multiple threads, coroutines, logic
 programming systems, etc.  That's why I wrote stack(s).  Actually, I
 should have written (partial) continuation(s).  There are any number
 of ways that an activation record for some procedure you modify could
 still be alive somewhere in the heap.  The issue can arise even with
 simple lazy data structures.  I don't think it's something we should
 punt on.  IMO anyway.

 What do you think?


Yes, you're right. I hadn't thought about those cases. This is a tricky
question.

But before we continue, are you sure that the right semantics is to modify
all of the continuations? In particular, let's say you have a function like
this:

(define (func x)
  (+ x 2 (my-special-function x)))

And my-special-function captures its continuation, k. Later on, you modify
func to be this:

(define (func x)
  (+ x 2))

Now what is the continuation k supposed to do? That continuation doesn't
exist in the latest version of func. I think in this case you have to treat
it like a closure that is still holding on to the continuation that it was
passed (conceptually, at least) when it was called. So it would return to
the old version of func.

On the other hand, take the same example, but this time redefine +
instead of func. Now, does the continuation k call the new definition of
+, or the old one?

These really are questions for me. I don't know what the correct behavior
here is, but I think that if we can answer both of these questions, then we
know more or less what the correct thing to do is.

Noah


Re: [Guile-commits] GNU Guile branch, wip-rtl-cps, updated. v2.1.0-180-g0d0808a

2013-02-19 Thread Mark H Weaver
Hi Noah,

Noah Lavine noah.b.lav...@gmail.com writes:
 Yes, I completely agree with this. I didn't do that immediately
 because I'm trying to get the infrastructure for the general case
 working. I plan to implement un-boxing in CPS.

You still seem to be proceeding from the assumption that the conversion
to CPS will happen early, and that all optimizations will happen in CPS.
I continue to think that this is a bad idea, because of the order of
evaluation issue.

I realize that you intend to extend CPS with some way to express
unspecified evaluation order, but I'm not sure that is a good idea.
The fact that CPS fully specifies evaluation order is not merely an
undesirable flaw to be remedied.  It is fundamental to the nature of
CPS form, and an important part of what makes CPS desireable as an IR.
I fear that in trying to get the best of both worlds, you will instead
end up with the worst of both worlds.

I suspect that the way to get the best of both worlds is to do several
optimizations *before* conversion to CPS.  We already have an
increasingly sophisticated set of optimization passes implemented in
tree-il.  Those early passes already analyze whether or not lexicals
need to be mutable or not, and make several optimizations that depend on
having this information.

Do you intend to rewrite all of those passes for CPS?

Regards,
  Mark



Re: CPS Update

2013-02-19 Thread Mark H Weaver
Noah Lavine noah.b.lav...@gmail.com writes:
 But before we continue, are you sure that the right semantics is to
 modify all of the continuations? In particular, let's say you have a
 function like this:

 (define (func x)
   (+ x 2 (my-special-function x)))

 And my-special-function captures its continuation, k. Later on, you
 modify func to be this:

 (define (func x)
   (+ x 2))

 Now what is the continuation k supposed to do? That continuation
 doesn't exist in the latest version of func. I think in this case you
 have to treat it like a closure that is still holding on to the
 continuation that it was passed (conceptually, at least) when it was
 called. So it would return to the old version of func.

Yes.  If you redefine 'func', that only affects future calls to func,
not existing calls.

 On the other hand, take the same example, but this time redefine +
 instead of func. Now, does the continuation k call the new
 definition of +, or the old one?

In your example above, it's unspecified, because the operator and
operands of a procedure call are evaluated in unspecified order.
Therefore, an implementation is allowed to evaluate '+' either before or
after it evaluates (my-special-function x).

However, consider this slightly different example:

(define (func x)
  (let ((r (my-special-function x)))
(+ x 2 r)))

Here, (my-special-function x) must be evaluated before evaluating '+'.
Evaluating '+' means to fetch the value stored in the location denoted
by '+'.  Therefore, if '+' is rebound during the call to
'my-special-function', then the new binding for '+' must be used.

This is a case where on-stack-replacement is needed to implement the
correct semantics.

To summarize, when you rebind a function 'foo', it is not the existing
activation records for 'foo' that you need to worry about.  Instead, you
need to worry about existing activation records for all compiled
procedures 'bar' that incorporated assumptions about 'foo'.

Thanks for working on this,

 Mark



Re: Precedence for reader extensions

2013-02-19 Thread Mikael Djurfeldt
On Tue, Feb 19, 2013 at 4:41 PM, Mark H Weaver m...@netris.org wrote:
 Mikael Djurfeldt mik...@djurfeldt.com writes:
 On Tue, Feb 19, 2013 at 12:33 AM, Mark H Weaver m...@netris.org wrote:
 Mikael Djurfeldt mik...@djurfeldt.com writes:
 I propose to simplify this to only two levels:

 1. %read-hash-procedures
 2. predefined syntax

 It turns out that the change I propose above was already implemented
 in read.c.  The effect just wasn't visible due to a bug in flush_ws
 which caused all #! to be erroneously removed if they exist as the
 outermost expression.

 I'm not sure that I consider this a bug.

In this reply I've attached a file mit-reader-scm which installs a
hash-read-procedure for #\!.

What I wanted to say above is that scm_read_sharp (in HEAD) is
implemented with the priorities I list above while flush_ws is
implemented with other priorities.  Here's a demo of the consequences
of this bug:

scheme@(guile-user) (load mit-reader.scm)
scheme@(guile-user) (quote #!optional)
... !# hi)
$1 = hi
scheme@(guile-user) '#!optional
$2 = #:optional

 [...]
 I'm uncomfortable with globally overriding standard read syntax.  In a
 large scheme system such as Guile, there are many modules that use
 'read' and expect it to act in accordance with standard lexical
 conventions.

Well, in the mit-scheme compatibility module, my intention was to use
dynamic-wind to modify #!-syntax while loading mit-scheme-specific
files.  Note that %read-hash-procedures is a fluid, so this will be
absolutely local and won't leak out in any way to the rest of the
system.

 The problem with this approach is that it does not compose.

Let's now patch guile according to the diff I sent... there!

scheme@(guile-user) (load mit-reader.scm)
scheme@(guile-user) (quote #!optional)
$1 = #:optional
scheme@(guile-user) '#!optional
$2 = #:optional
scheme@(guile-user) (quote #!hi!# #!optional)
$3 = #:optional

My take on this is:

* The %read-hash-procedures API is not pretty

* The suggested change doesn't make things prettier

* The suggested change *does* make things conceptually simpler and
more flexible (= you can always override hash syntax if you want;
compared to the current: you can override #| but not other hash
syntax)

* The suggested change fixes a bug

* The suggested change does compose and different syntax can be
confined to a module by using dynamic-wind

Best regards,
Mikael


mit-reader.scm
Description: Binary data


Re: [Guile-commits] GNU Guile branch, wip-rtl-cps, updated. v2.1.0-180-g0d0808a

2013-02-19 Thread Noah Lavine
Hello,

On Tue, Feb 19, 2013 at 11:03 AM, Mark H Weaver m...@netris.org wrote:

 Hi Noah,

 Noah Lavine noah.b.lav...@gmail.com writes:
  Yes, I completely agree with this. I didn't do that immediately
  because I'm trying to get the infrastructure for the general case
  working. I plan to implement un-boxing in CPS.

 You still seem to be proceeding from the assumption that the conversion
 to CPS will happen early, and that all optimizations will happen in CPS.
 I continue to think that this is a bad idea, because of the order of
 evaluation issue.

 I realize that you intend to extend CPS with some way to express
 unspecified evaluation order, but I'm not sure that is a good idea.
 The fact that CPS fully specifies evaluation order is not merely an
 undesirable flaw to be remedied.  It is fundamental to the nature of
 CPS form, and an important part of what makes CPS desireable as an IR.
 I fear that in trying to get the best of both worlds, you will instead
 end up with the worst of both worlds.

 I suspect that the way to get the best of both worlds is to do several
 optimizations *before* conversion to CPS.  We already have an
 increasingly sophisticated set of optimization passes implemented in
 tree-il.  Those early passes already analyze whether or not lexicals
 need to be mutable or not, and make several optimizations that depend on
 having this information.

 Do you intend to rewrite all of those passes for CPS?


That's a fair point. I do think that some of those optimizations would work
better in CPS, but even if that's true, I don't want to port them all at
once. I agree that the goal should be to have a compiler in which some
optimizations are done in Tree-IL and some in CPS, and once we have that,
we can play with which optimizations happen where.

So for now, yes, you are completely correct. However, you might like my
other reason better: the Tree-IL-CPS compiler can't compile any cases that
really need mutable variable slots, so I had to test mutable variables with
examples that really don't need them. Once the Tree-IL-CPS compiler can
handle interesting cases, then we can start optimizing the uninteresting
ones away.

Best,
Noah


Re: Precedence for reader extensions

2013-02-19 Thread Mikael Djurfeldt
On Tue, Feb 19, 2013 at 5:42 PM, Mikael Djurfeldt mik...@djurfeldt.com wrote:
 * The suggested change does compose

What I meant here is that it does compose with the built-in syntax.

Of course, the %read-hash-procedures API by itself doesn't
automatically compose if multiple user-defined modules use it to
introduce new syntax.  (If these modules take care to preserve
previously installed procedures, it can compose.)

The API you suggest would compose much easier, but to me it feels like
just another specialized solution.  What we would really need is
something like Ludovic's guile-reader.

But I won't be stubborn regarding this.  If someone else wants to
implement another way of supporting #!optional and #!rest that is fine
by me.  I regard my diff simply as a bug fix and cleanup (removing
unreachable code).



Re: CPS Update

2013-02-19 Thread Stefan Israelsson Tampe
Hi,

1. Does any other system recompile stuff that set! a + operation
2. Isn't the least we should do to warn when a user set! + as I did in
the last email
3. Wouldn't it be a good idea to allow a user to specify which basic
vm op's would be translated
   to a macine instruction or not. So say that I would like to count
the number of scheme + guile uses at
   startup, then I could specify in a configuration that + should not
be comiled to a vm-op and then recompile guile and then use set!

On Sat, Feb 16, 2013 at 5:29 PM, Noah Lavine noah.b.lav...@gmail.com wrote:
 Hello,


 On Sat, Feb 16, 2013 at 2:39 AM, Stefan Israelsson Tampe
 stefan.ita...@gmail.com wrote:

 Isn't the primitiveness decided by tree-il? you wil get a (primcall
 ...) tree il element and then should know how to emit a
 corresponding primitive instruction(s).


 Oh, you're right. I was thinking about that because I don't run the Tree-IL
 optimizers when I test it, so I don't get any Tree-IL primitives. Eventually
 maybe the primitive generation should happen in CPS, but I don't think it
 has to happen all at once.


 Anyway I think that your
 conclusion is right, it would not make sense to support overwriting
 these primitives dynamically, but

 scheme@(guile-user) (set! + (lambda x (apply * x)))
 scheme@(guile-user) (+ 2 3)
 $1 = 6
 scheme@(guile-user) (define (f x y) (+ x y))
 scheme@(guile-user) ,x f
 Disassembly of #procedure f (x y):

0(assert-nargs-ee/locals 2)  ;; 2 args, 0 locals
2(local-ref 0)   ;; `x'
4(local-ref 1)   ;; `y'
6(add)
7(return)

 So things are not consistent!


 Good example! This looks like a bug to me. I think I read that loading GOOPS
 turns things like '+ into generic operations - that might be a case where
 this matters a lot.

 I have thought a bit about how to fix this. The module system already allows
 us to be notified whenever a variable changes, so it would be easy to watch
 all of the variables in (guile) and recompile procedures when they change. I
 might take a look at this soon.


 BTW
 If you like I could work on getting define* and lambda* to work, I
 have that code in my branch and should be able
 to make it work on your branch as well. WDYT?


 Thanks, but I haven't even gotten far enough to think about this. I'm still
 working on getting all of the basic features going. After that I would
 definitely like define* and lambda*.

 Noah



 /Stefan

 On Sat, Feb 16, 2013 at 1:53 AM, Noah Lavine noah.b.lav...@gmail.com
 wrote:
  Hello,
 
  The wip-rtl-cps branch has been rebased again (on top of wip-rtl). It
  now
  includes support for toplevel references and sets, thanks mostly to
  Andy's
  work on supporting them in RTL. (Although you shouldn't kick that part
  of it
  too hard just yet; I think I know where it will break.) Other highlights
  include using the top-level variable support to evaluate (+ 3 4)
  correctly.
 
  Overall, I think it's coming along well. The parts of Tree-IL that are
  left
  to implement are local mutable variables (should be easy after toplevel
  ones), module references and sets (very similar to top-level ones),
  closures, and the dynamic environment stuff. Local mutable variables are
  my
  next project, and then I think closures.
 
  One question I've had is, can we assume that the variables in the
  (guile)
  module are immutable? I think the current compiler does this. Otherwise
  there's no correct way to inline primitive procedures like + unless we
  have
  a way to invalidate our compiled code and recompile it (which I would
  like
  to have anyway, but that's a different story).
 
  Best,
  Noah
 





Re: Precedence for reader extensions

2013-02-19 Thread Mikael Djurfeldt
On Tue, Feb 19, 2013 at 5:42 PM, Mikael Djurfeldt mik...@djurfeldt.com wrote:
 * The suggested change *does* make things conceptually simpler and
 more flexible (= you can always override hash syntax if you want;
 compared to the current: you can override #| but not other hash
 syntax)

Just to try to be clear:

What I write above is not strictly true.  The current Guile *already*
allows you to override standard syntax, even without my changes.  What
my changes do is to cleanup the old mechanism so that it doesn't fail
when whitespace is involved.

An example of how it currently fails is that you *can* override when
you spell quote using single quote ('OBJECT) since no whitespace is
involved while you cannot override when you spell quote using the
symbol quote ((quote OBJECT)) since there's whitespace to be
swallowed before the OBJECT.

I do respect the attitude that the user shouldn't be able to override
standard syntax, even though I don't think it matters much given the
state of the current mess.  But I think you agree that we either need
to apply my fix (making the current overriding mechanism useful) or
fix scm_read_sharp so that it conforms with the behavior of flush_ws.