multi scoping

2005-09-04 Thread Luke Palmer
Here's a good Perl 6 final exam question:

Spot the mistake (hint: it's not in the math):

module Complex;

sub i() is export { 
Complex.new(0,1)
}
multi sub infix:<+> (Complex $left, Complex $right) is export {
Complex.new($left.real + $right.real, $left.imag + $right.imag);
}
multi sub infix:<*> (Complex $left, Complex $right) is export {
Complex.new(
$left.real * $right.real - $left.imag * $right.imag,
$left.real * $right.imag + $right.real * $left.imag)
}
# ...

Give up?

When you add two complex numbers, you get into an infinite loop. 
That's because infix:<+> adds things using the plus operator, which
is, you guessed it, infix:<+>.  Now you'd think that multimethods
would handle that, but they don't because by defining "multi sub
infix:<+>" you are defining a *package* operator which *masks* the
global operator!  So this turns into infinite recursion.

By the way, this was done in Set.pm.  Pugs's scoping rules were
recently fixed, so suddenly the subtraction operator became an
infinite loop.

I see two solutions:

1) Disallow a "multi" to introduce a symbol if it masks another
symbol of the same name.  You must explicitly ask for masking by
predeclaring the symbol without "multi" somewhere before you define
the multi.  This still doesn't solve anything when you accidentally
put "is export" on an operator (as was done in Set.pm).
2) Make multi automatically find the symbol that you would have
referred to if the definition had not been there, and add a multi case
to that symbol.  So in the example above, the innermost infix:<+> that
existed before you said "multi" was *infix:<+>, so the multi
definition would basically infer that you meant to say multi
*infix:<+> and do the right thing.

There could also be some combination of the two.  Maybe something else
entirely.  Ideas?

Luke


Re: multi scoping

2005-09-04 Thread Yuval Kogman
On Sun, Sep 04, 2005 at 07:55:21 +, Luke Palmer wrote:
> Here's a good Perl 6 final exam question:
> 
> Spot the mistake (hint: it's not in the math):
> 
> module Complex;
> 
> sub i() is export { 
> Complex.new(0,1)
> }
> multi sub infix:<+> (Complex $left, Complex $right) is export {
> Complex.new($left.real + $right.real, $left.imag + $right.imag);
> }
> multi sub infix:<*> (Complex $left, Complex $right) is export {
> Complex.new(
> $left.real * $right.real - $left.imag * $right.imag,
> $left.real * $right.imag + $right.real * $left.imag)
> }
> # ...
> 
> Give up?
> 
> When you add two complex numbers, you get into an infinite loop. 
> That's because infix:<+> adds things using the plus operator, which
> is, you guessed it, infix:<+>.  Now you'd think that multimethods
> would handle that, but they don't because by defining "multi sub
> infix:<+>" you are defining a *package* operator which *masks* the
> global operator!  So this turns into infinite recursion.

I always saw scoping of multis as something that applies to the
variants...

multi sub foo {

}

{
my multi sub foo {

}

# the second variant is just for this scope, but 
neither masks
# the other
}

> You must explicitly ask for masking

I think this should be an option... You can either mask off a single
variant by declaring one that overrides it in a tighter scope, with
yadda yadda as the body, or you could ask a whole scope to be
omitted from the possible variants.

> 2) Make multi automatically find the symbol that you would have
> referred to if the definition had not been there, and add a multi case
> to that symbol.  So in the example above, the innermost infix:<+> that
> existed before you said "multi" was *infix:<+>, so the multi
> definition would basically infer that you meant to say multi
> *infix:<+> and do the right thing.

I don't agree with this... It takes the lexical scoping semantics
out of things.

If multi's would cascade WRT to the scope of their definition, but
not mask, things should DWIM most of the time.

Please remember that when you declare a new multi you are usually
ammending to a commonly used operator, in order to extend it's
behavior in the scope that there is new data which much behave
accordingly.

There is one more problem though:

class Complex {
multi sub &infix:<*> { ... }
}

package Moose;
use Complex;
use SomeMathLib ;

...

function($some_complex_number); # if function calls infix:<*> on
# it's operand, somehow... What happens?

-- 
 ()  Yuval Kogman <[EMAIL PROTECTED]> 0xEBD27418  perl hacker &
 /\  kung foo master: /me spreads pj3Ar using 0wnage: neeyah!!!



pgpTDDK5o2dCa.pgp
Description: PGP signature


Re: multi scoping

2005-09-04 Thread Luke Palmer
On 9/4/05, Yuval Kogman <[EMAIL PROTECTED]> wrote:
> I always saw scoping of multis as something that applies to the
> variants...
> 
> multi sub foo {
> 
> }
> 
> {
> my multi sub foo {
> 
> }
> 
> # the second variant is just for this scope, but 
> neither masks
> # the other
> }

Reading over A12 again (in the section "Multiple Dispatch"), it
appears that you are right.

So let's figure out if that's actually the right way or the wrong way.
 I don't understand the second-to-last paragraph of that section,
which apparently explains why single variants mask.

> > You must explicitly ask for masking
> 
> I think this should be an option... You can either mask off a single
> variant by declaring one that overrides it in a tighter scope, with
> yadda yadda as the body, or you could ask a whole scope to be
> omitted from the possible variants.

Just to clarify, is this what you are suggesting?

multi foo (Int $x) { $x + 1 }
multi bar (Int $x) { $x + 1 } 
{
my sub foo ($x) {...}
my multi foo (Str $x) { "x" ~ $x }

my multi bar (Str $x) { "x" ~ $x }

bar("hi"); # xhi
bar(1);# 2
foo("hi"); # xhi
foo(1);# error, no compatible sub found
}

Though if that's the case, then it almost feels to me like the "multi"
should go before the "my".  But that would be screwing with the
consistency of the grammar a little too much, I think.

> > 2) Make multi automatically find the symbol that you would have
> > referred to if the definition had not been there, and add a multi case
> > to that symbol.  So in the example above, the innermost infix:<+> that
> > existed before you said "multi" was *infix:<+>, so the multi
> > definition would basically infer that you meant to say multi
> > *infix:<+> and do the right thing.
> 
> I don't agree with this... It takes the lexical scoping semantics
> out of things.

Oh, by the way, I was suggesting that a *bare* "multi" would do this. 
If you said "our" or "my", you are stating exactly what you mean. 
Well, almost (what does "my multi foo" mean if there is an outer
lexical multi foo -- mask or append?).

> There is one more problem though:
> 
> class Complex {
> multi sub &infix:<*> { ... }
> }
> 
> package Moose;
> use Complex;
> use SomeMathLib ;
> 
> ...
> 
> function($some_complex_number); # if function calls infix:<*> on
> # it's operand, somehow... What happens?

This is actually my *whole* problem, and the reason that I don't think
that variants should mask, but entire symbols should mask.  It seems
like you'd use a lexically scoped multi variant about as much as you'd
use a lexically scoped method on a class.  Can you think of a use for
that?

Isn't the point of lexical scoping so that you don't have to worry
whether somebody else called something the same thing you did?  I can
picture this:

multi combine (Any $x, Any $y) { ZCombinator.new($x, $y) }
multi combine (@x, @y) { ZList.new([ @x, @y ]) }   # concat
multi combine (Str $x, Str $y) { ZStr.new($x ~ $y) }

# ... many lines pass ...

sub process($x, $y) {
my multi combine (Any $a, Any $b) { die "Cannot combine" }
my multi combine (Int $a, Int $b) { $a + $b }

return combine($x, $y);
}

process("Foo", "Bar");
# Gets back a... what? ZStr?  What the heck is that

Clearly the author of process intended that two integers get added and
anything else dies.  He was not aware of the combine defined many many
lines above.   But he was smart and made his multis lexically scoped
so he didn't have to worry.

Really, he should have written process like so:

sub process($x, $y) { 
my sub combine ($a, $b) {...}
my multi combine (Any $a, Any $b) { die "Cannot combine" }
my multi combine (Int $a, Int $b) { $a + $b }

return combine($x, $y);
}

That case, to me, seems a lot more common than lexically overriding a
multi variant.  But I am open to counterexamples.

Assuming we have no information about the frequency, there is another
question to ask whether it makes sense to override or extend:  Is it
natural to do it both ways?  That is, does it feel right?  (Please,
get your mind out of the gutter and pay attention! :-)

It seems fairly natural when we go with the extension mechanism that
A12 seems to propose.  "multis extend, subs mask", so if you want to
mask, you just define it as a sub first.  It's a little awkward, but
it'll do.  The other way, however, is not nearly as natural:

# let's say that he wanted process() to do what I said he didn't intend
sub process($x, $y) { 
my multi combine (Any $x, Any $y) { OUTER::combine($x, $y) }
my multi combine (Int $x, Int $y) 

FYI: Lambda Calculus on Perl 6

2005-09-04 Thread Dan Kogai

Folks,

I recently needed to write a series of codes on lambda calculus in  
perl.  As MJD has shown Perl 5 can handle lambda calculus but I am  
beginning to get tired of whole bunch of 'my $x = shift' needed.



  our $ZERO =
  sub { my $f = shift;
  sub { my $x = shift; $x }};
  our $SUCC =
  sub { my $n = shift;
sub { my $f = shift;
  sub { my $x = shift;
$f->($n->($f)($x)) }}};
  our $ADD =
  sub{ my $m = shift;
   sub { my $n = shift;
 sub { my $f = shift;
   sub { my $x = shift;
 $m->($f)($n->($f)($x)) ;
  our $MULT =
  sub { my $m = shift;
sub { my $n = shift;
  sub { my $f = shift;
$m->($n->($f)) }}};
  our $POW =
  sub { my $m = shift;
sub { my $n = shift;
  $n->($m) }};

And I found that these can be made much, much simpler and more  
intuitive with Perl 6, even more so than scheme!


  our $ZERO = sub($f){ sub($x){ $x }};
  our $SUCC = sub($n){ sub($f){ sub($x){ $f.($n.($f)($x)) }}};
  our $ADD  = sub($m){ sub($n){ sub($f){ sub($x){ $m.($f)($n.($f) 
($x)) ;

  our $MULT = sub($m){ sub($n){ sub($f){ $m.($n.($f)) }}};
  our $POW  = sub($m){ sub($n){ $n.($m) }};

You can even make it simpler by removing dots but I leave it that way  
because it looks more like the original notation that way (i.e.   
zero := λf.λx.x).


Runs perfectly fine on Pugs 6.2.8.  Add the code below and see it for  
yourself.


  my $one = $SUCC.($ZERO);
  my $two = $SUCC.($one);
  my $four= $ADD.($two)($two);
  my $eight   = $MULT.($two)($four);
  my $sixteen = $POW.($four)($two);
  for($one, $two, $four, $eight, $sixteen) -> $n {
  $n.(sub($i){ 1 + $i})(0).say
  };

Maybe we can use this for advocacy.

Dan the Perl 6 User Now

P.S.  I am surprised to find Pugs does not include this kind of  
sample scripts.

 

Re: FYI: Lambda Calculus on Perl 6

2005-09-04 Thread Autrijus Tang
On Mon, Sep 05, 2005 at 12:35:36PM +0900, Dan Kogai wrote:
> And I found that these can be made much, much simpler and more  
> intuitive with Perl 6, even more so than scheme!
> 
>   our $ZERO = sub($f){ sub($x){ $x }};
>   our $SUCC = sub($n){ sub($f){ sub($x){ $f.($n.($f)($x)) }}};
>   our $ADD  = sub($m){ sub($n){ sub($f){ sub($x){ $m.($f)($n.($f) 
> ($x)) ;
>   our $MULT = sub($m){ sub($n){ sub($f){ $m.($n.($f)) }}};
>   our $POW  = sub($m){ sub($n){ $n.($m) }};

Nice!  Also the pointy notation may or may not be clearer:

-> $f { -> $x { $x } }

Also, you can use the & sigil:

our &SUCC := sub(&n){ sub(&f){ sub(&x){ f(n(&f)(&x)) }}};

which may or may not be clearer... probably not, come to think about it.

> P.S.  I am surprised to find Pugs does not include this kind of  
> sample scripts.

I'm surprised to find dan-san is not a Pugs committer.  I've remedied
this situation by sending you an invitation.  The commit URL is the
same as the anonymous checkout svn URL.

Please commit them into the suitable examples/ subdirectory, probably
"algorithms".  Also please add yourself to AUTHORS.  Welcome aboard!

Thanks,
/Autrijus/


pgpERLqoLpAGo.pgp
Description: PGP signature