Re: multisub.arity?

2005-09-07 Thread Larry Wall
On Tue, Sep 06, 2005 at 06:19:01PM +0300, Yuval Kogman wrote:
: On Tue, Sep 06, 2005 at 13:28:24 +, Luke Palmer wrote:
: 
: This should still work:
: 
:  sub map (code, [EMAIL PROTECTED]) {
:  gather {
:  my @args = @list.splice(0, code.arity);
:  take code([EMAIL PROTECTED]);
:  }
:  }
: 
:   multi sub foo ( ... ) { ... } 
:   multi sub foo ( ... ) { ... }
: 
:   my @mapped = map foo ...;
: 
: I think this is inconsistent.
: 
: There is another option though:
: 
:   sub map (code, [EMAIL PROTECTED]) {
:   gather {
:   take code.mutably_bind_some(@list); # removes stuff
:   # from @list
:   }
:   }
: 
: The code object can then look for suitable multimethod alternatives
: for the arguments in question, avoid that alltogether, dispatch
: based on the arity of the first alternative, dispatch based on the
: arity of the most general alternative, or whatever.

Yes, I think that's closer to the mark.  The basic problem is having
to deal with the arity *at all*, much as having to deal with string
positions as integers is becoming wronger as we get into Unicode.
What we're looking for here is a better abstraction, and I suspect that
this abstraction involves defining a class of dispatch that assumes an
implicit slurpy on the end of everything called, and simply returns
any unbound arguments as the unshifted part of the list.  It could
maybe even be made to work right with respect to ? parameters that
might or might bind based on type.

It's very much like an inside-out .assuming, only it does the actual
call, and leaves the residue.  Another view is that it's basically
turning a normal call into a mutator call of the splice variety.
So maybe map is just

sub map (code, [EMAIL PROTECTED]) {
gather {
take @list.splice(code);
}
}

or some such.

Larry


Re: multisub.arity?

2005-09-07 Thread Luke Palmer
On 9/7/05, Damian Conway [EMAIL PROTECTED] wrote:
 Luke wrote:
   In that last case though, this is not equivalent to the above:
  
   given code.arity {
   when 2 { code(1,2) }
   when 1 { code(1) }
   }
  
   That may be a little... surprising.  Still, it's fixed to succeed
   either way, so that's probably okay, right?
 
 It's not surprising at all. The order of Cwhen tests (usually) matters,
 because a series of Cwhen statements (usually) short-circuits.

Okay, fair enough.  The reason that I thought it was surprising is
because 1 and 2 are usually orthogonal patterns.  But, I guess in the
presence of junctions I'm not able to assume that (as I'll explain in
my conclusion later, junctions make it impossible for me to assume
just about anything).

   Junctions are logical travesty,
 
 Well, that's very emotive, but I don't believe it's either a useful or an
 accurate characterization. I would agree that junctions can be logically
 *sophisticated*, but then I'd argue that *all* programming constructs are 
 that.

No, that wasn't emotive, that was a logical statement explaining that
junctions are not logical.  Maybe that's what I should have said
before.  See below.

   and it seems to me that they cease to be useful in all but the
   situations where the coder knows *everything*.
 
 What does that mean, exactly? How can anyone *ever* write sensible code
 without knowing what kind of values they're processing?

Have you ever heard of generic programming?

How can any *ever* write a sensible generic Set class when you are
required to know what kind of thing you have in the set?

 Otherwise hard things that junctions make a lot easier:
 
  if 0 = @coefficients  1 {...}

Ummm... that's an array in numeric context...

  if 0 = all(@new_coefficients)  all(@prev_coefficients)  1 {...}

I'll give you this one.  This takes twice the amount of code.

if 0 = min(@new_coefficients)  
max(@new_coeffficients)  min(@prev_coefficients) 
max(@prev_coefficients)  1   {...}

  if 0 = all(@new_coefficients) != all(@prev_coefficients)  1 {...}
 
  if 0 = any(@new_coefficients) != all(@prev_coefficients)  1 {...}

Okay, you may be convincing me here.  Until I find a good way to do
these.  The fact that I have to look is already junctions++.

  if ! defined one(@inputs) {...}

I don't get how this could possibly be useful.

   $a = any($a, $b).
   any($a, $b) = $b.
   Therefore, $a = $b.

...

  Luke is no smarter than Luke or Luke is no smarter than a rock.
  Luke is no smarter than a rock or a rock is no smarter than a rock.
 
 Remove the false assertions (since nothing correct can ever be deduced
 from a false assertion):

Sure, everything correct can be deduced from a false premise.  Just...
um... everything incorrect can too.  :-)

  Luke is no smarter than Luke
a rock is no smarter than a rock.
 
 But now the remaining assertions support *no* new conclusion.

And this is based on lexical expansion.  Which is cool.  In fact, once
upon a time I was going to propose that junctions are a purely lexical
entity, expanded into greps and whatnot by the compiler; that you
can't ever stick them in variables.  Your examples above are just more
attestment to that, since there is not one of them that I can't write
confining all junctions to lexical areas.

I think you missed my original point.  Here is a similar proof:

Assume for the sake of contradiction that:
  For all $a,$b,$c:
$a  $b  $b  $c implies $a  $c;

let $a = 3, $b = any(1,4), and $c = 2

Substituting:
3  any(1,4)  any(1,4)  2 implies 3  2
   True  implies False
Contradiction!

I just proved that  is not transitive.

I can do that for every boolean operator that Perl has.  They no
longer have any general properties, so you can't write code based on
assumptions that they do.   In particular, testing whether all
elements in a list are equal goes from an O(n) operation to an O(n^2)
operation, since I can't make the assumption that equality is
transitive.

So my original point was that, as cool as junctions are, they must not
be values, lest logical assumptions that code makes be violated.  I
can tell you one thing: an ordered set class assumes that  is
transitive.  You had better not make an ordered set of junctions!

Luke


Re: multisub.arity?

2005-09-07 Thread Brent 'Dax' Royal-Gordon
On 9/7/05, Luke Palmer [EMAIL PROTECTED] wrote:
 And this is based on lexical expansion.  Which is cool.  In fact, once
 upon a time I was going to propose that junctions are a purely lexical
 entity, expanded into greps and whatnot by the compiler; that you
 can't ever stick them in variables.  Your examples above are just more
 attestment to that, since there is not one of them that I can't write
 confining all junctions to lexical areas.

Here's a Real Live Perl 6 module I wrote recently.  I've omitted a few
magic portions of the code for clarity.

module Trace-0.01-BRENTDAX;

my $active;
...

sub activate(*%newtags) {
$active |= any(keys %newtags);
}

sub trace([EMAIL PROTECTED] is copy, *%to is copy) is export {
...
if $active eq any('all', keys %to) {
...
print $ERR: @msg;
return [EMAIL PROTECTED] #but true;
}
return;
}

I rather like that non-lexical use of junctions.

-- 
Brent 'Dax' Royal-Gordon [EMAIL PROTECTED]
Perl and Parrot hacker


Re: multisub.arity?

2005-09-07 Thread Luke Palmer
On 9/7/05, Brent 'Dax' Royal-Gordon [EMAIL PROTECTED] wrote:
 Here's a Real Live Perl 6 module I wrote recently.  I've omitted a few
 magic portions of the code for clarity.

Thanks for real live perl 6 code.  It's always nice to have real examples.

However, I'm arguing for logical stability without losing expressive
power.  The case that convinces me is the one where something becomes
a lot harder without lexical junctions.  This one doesn't:

 module Trace-0.01-BRENTDAX;
 
 my $active;
 ...
 
 sub activate(*%newtags) {
 $active |= any(keys %newtags);
   @active.push(keys %newtags);
 }
 
 sub trace([EMAIL PROTECTED] is copy, *%to is copy) is export {
 ...
 if $active eq any('all', keys %to) {
  if any(@active) eq any('all', keys %to) {
 ...
 print $ERR: @msg;
 return [EMAIL PROTECTED] #but true;
 }
 return;
 }

And that is clearer to me at least.  You can tell the nature of the
comparison: that you're checking a list of pattern against a list of
active objects, rather than a list of patterns against a single
object, which is what it looked like before.  YMMV on that angle,
though.

The reason I think that this approach won't lose expressive power is
mostly because of our new Set class.  The one remaining thing is when
you build up a nested junction in terms of ors and ands and check
that, as was given in one of Damian's old examples.  I really haven't
come up with a reason you'd want to do that yet, but I *am* looking. 
I'm not on a mission to destroy junctions, really. I'm just on a
mission to make things make sense. :-/

Luke


RE: multisub.arity?

2005-09-07 Thread Thomas Sandlass
HaloO,

Luke wrote:
 I just proved that  is not transitive.

 I can do that for every boolean operator that Perl has.  They no
 longer have any general properties, so you can't write code based on
 assumptions that they do.   In particular, testing whether all
 elements in a list are equal goes from an O(n) operation to an O(n^2)
 operation, since I can't make the assumption that equality is
 transitive.

I fully second this. I guess the axiom of excluded middle simply doesn't
hold for the four junction types, nor are they ordered.
(Sidenode as non-native: is the last usage of 'nor' incorrect?)
But so will be many other types.

Could someone point me to a mathematical paper or general material what
axiom system applies to junctions?


 So my original point was that, as cool as junctions are, they must not
 be values, lest logical assumptions that code makes be violated.  I
 can tell you one thing: an ordered set class assumes that  is
 transitive.  You had better not make an ordered set of junctions!

With a certain stricture on defining the meaning of tokens like  I
think Perl6 shouldn't join poor C++ with its fixed set of operators
to overload ops arbitrarily with unrelated meaning. Unicode has enough
to offer. But back to the point that Luke made: all comparison ops don't
apply to junctions which spoils a big advantage and deminishes junctions
to a nice form to avoid chained boolean connectives like || with an any().

To me junctions always felt more code like than value like. They
are even some kind of meta ops that consume boolean comparison ops
in terms of another boolean connective (any = or, all = and, etc.)
Why not reflect that in the syntax and make them like for, map,
grep etc? I mean with the junction name in front:

   if all( @new_coefficients  @prev_coefficients ) {...}

or Brent's example

   if any( $active eq ['all', keys %to] ) {...}

The desugared forms would be simple ternary calls:

  if any( infix:{''}, $active, ['all', keys %to] ) {...}

The return value would need to be lists of tuples to allow
combining junctions:

  if any($x  all(@values  0))

That latter property also gives

  for all(@values  0) - $x { say sqrt $x }

And as all other code types junctions are subject to currying
and later usage like other code refs

  x_in = any.assuming( lhs = $x, op = infix:== );

  if x_in( @array ) {...}

With (curried) junctions travelling in  vars I guess people
have less problems with the auto-threading behaviour as well.

Hmm, and we win back the three single character infix ops |, 
and ^. The simple example

  if $x == 1|2|3 {...}

then reads

  if any($x == [1,2,3]) {...}

I admit though, that the any might be optically attached to the
$x and not to the implicitly hyperated ==. Thus the idiom needs
to be spelled

  if any([1,2,3] == $x) {...}

TSa.



Re: multisub.arity?

2005-09-07 Thread Damian Conway

Luke wrote:

 Okay, fair enough.  The reason that I thought it was surprising is
 because 1 and 2 are usually orthogonal patterns.

It depends what they're doing. Matched against a regex like /[12]/ they're
not orthogonal either.


  Junctions are logical travesty,

Well, that's very emotive, but I don't believe it's either a useful or
an accurate characterization. I would agree that junctions can be
logically *sophisticated*, but then I'd argue that *all* programming
constructs are that.

 No, that wasn't emotive,

Travesty is not an emotive word???


 that was a logical statement explaining that junctions are not logical.

Right. So Luke's statement is a logical travesty isn't an
unsubstantiated emotive assertion either? ;-)



 Have you ever heard of generic programming?

 How can any *ever* write a sensible generic Set class when you are
 required to know what kind of thing you have in the set?

By restricting the implementation to behaviours that are universal (see
below). Or by restricting the set of contained values to values for
which the implemented behaviours work correctly. That is: just like any
other kind of programming.


Otherwise hard things that junctions make a lot easier:

 if 0 = @coefficients  1 {...}

 Ummm... that's an array in numeric context...

Yes. A mistake. I (fairly obviously) meant:

   if 0 = all @coefficients  1 {...}


 if ! defined one(@inputs) {...}

 I don't get how this could possibly be useful.

That doesn't mean it's not. ;-)

You might use exactly that test to initiate autocomputation of the one
missing value. For example, if you're given volume, pressure, and
temperature values of a gas, but one is undefined, then you might
want to compute it from the others. That test would tell you that you need to 
(and that you have enough information to do so).




 In particular, testing whether all
 elements in a list are equal goes from an O(n) operation to an O(n^2)
 operation, since I can't make the assumption that equality is
 transitive.

That's simply not true. It is perfectly possible to write an O(n) list
equality test on a list that may include junctions. You simply need an
elementwise equality test that handles junctions correctly. Let's call it
Csame:

# Junctions same if same type, same number of values, and same values...
multi sub same(Junction $j1, Junction $j2) {
return 0 if $j1.type != $j2.type || $j1.values != $j2.values;
return [] same($j1.values, $j2.values);
}

# Junctions and non-junctions never the same...
multi sub same(Junction $j, Item $i) is reversible {
return 0;
}

# Non-junctions same if == (or whatever base-case test you prefer)
multi sub same(Item $i1, Item $i2) {
return $i1 == $i2;
}

# List elems equal if each pair of adjacent elements is the same...
sub all_equal(@list) {
return [] same(@[EMAIL PROTECTED], @list[1...]);
}



 So my original point was that, as cool as junctions are, they must not
 be values, lest logical assumptions that code makes be violated.  I
 can tell you one thing: an ordered set class assumes that  is
 transitive.  You had better not make an ordered set of junctions!

You can rest assured that I won't try to make one. Because it doesn't
makes *sense* to even talk about an ordered set of junctions. Any more
than it makes sense to talk about an ordered set of vectors, or lists,
or regexes. Will you also be recommending that lists and regexes not be
values???

More seriously, since the ordered set's methods presumably *won't* use
(Item(+)Junction) type arguments, why will this be a problem? The
ordered set will never *see* junctions.

Damian


Re: multisub.arity?

2005-09-07 Thread Luke Palmer
On 9/8/05, Damian Conway [EMAIL PROTECTED] wrote:
 Luke wrote:
 
   Okay, fair enough.  The reason that I thought it was surprising is
   because 1 and 2 are usually orthogonal patterns.
 
 It depends what they're doing. Matched against a regex like /[12]/ they're
 not orthogonal either.

Well, then they're not patterns; they're the things being matched
against a pattern.  But then you could think of junctions in the same
way.  In fact, the proposal was to do precisely that.  But I think
you've knocked me off of that one (with your multiple junctions in
the same expression examples).

   that was a logical statement explaining that junctions are not logical.
 
 Right. So Luke's statement is a logical travesty isn't an
 unsubstantiated emotive assertion either? ;-)

Hey. I backed up my claim with a proof!  Let's settle on It doesn't
matter! :-)

   if ! defined one(@inputs) {...}
  
   I don't get how this could possibly be useful.
 
 That doesn't mean it's not. ;-)

You don't need to sell me on these, by the way.  You already did. 
That was just a comment on this particular example.

   So my original point was that, as cool as junctions are, they must not
   be values, lest logical assumptions that code makes be violated.  I
   can tell you one thing: an ordered set class assumes that  is
   transitive.  You had better not make an ordered set of junctions!
 
 You can rest assured that I won't try to make one. Because it doesn't
 makes *sense* to even talk about an ordered set of junctions. Any more
 than it makes sense to talk about an ordered set of vectors, or lists,
 or regexes. Will you also be recommending that lists and regexes not be
 values???

Well, none of those things define a  operator.  I suppose one could
say that lists do, but he'd be wrong.  They coerce to numbers, which
in turn have a  operator, so you'd end up with a set of numbers...

I think I see where you're coming from though.  If we go with
Haskell's type classes, then I could see how this would work. 
Junction simply wouldn't do Eq or Ord (equality or ordering), since it
doesn't meet the prerequisites for doing those type classes
(transitivity and antisymmetry).  Then the Junctive  would be about
as similar to numeric  as IO::All's  is, at least from Perl's
perspective.

 More seriously, since the ordered set's methods presumably *won't* use
 (Item(+)Junction) type arguments, why will this be a problem? The
 ordered set will never *see* junctions.

Set of Junction?  If the methods are declared with parameters ::T (the
parameterization type of Set), then it certainly would accept
junctions.

Admittedly, that should just fail since it doesn't make any sense. 
Admittedly, it would probably end up succeeding and giving you an
infinite loop, and then comp.lang.perl.misc or #perl would give you a
belated compile-time error.  Or Set could say No junctions!, but
then we're getting into special cases.

Hmm, incidentally, if we have:

theory Value[::T] {
# in order to do Value, eqv must be transitive:
# $a eqv $b and $b eqv $c implies $a eqv $c
multi infix:eqv (::T, ::T -- Bool) {...}
# ... some useful methods
}

(For those of you following along at home, don't worry if you don't
know what a theory is, I haven't proposed it yet.  For those of you
lambdacamels following along at home, a theory is basically a type
class.)

Then Junction shouldn't do Value, since it doesn't meet one of the
implicit requirements.  Since Sets only operate on Values (no
reference types allowed: they can change under your feet), then a Set
would reject a Junction as a valid parameterization.  Oh, I guess
Junction's absence of the Ordered class already did that.

Alright, this seems to be working out mathematically if we get type
classes.  It's really not a solution I like much, as it's basically
saying yeah, junctions exist, but they really don't participate in
the algebra of your program.  Actually, since they don't do Value,
you can't make any aggregate of Junctions whether you declare it or
not (sub parameters are still okay when declared though; they don't
have to be Values).

Okay, with that, my position changes.  I no longer see anything wrong
with Junctions from a pure perspective.  I still think it's wrong to
Humans to have something that looks ordered but in fact isn't, and I
still think that if Junctions are values, you ought to be able to
metaprogram with them.  But I don't really have any ideas other than
the ones I've proposed in this thread and the one involving Haskell's
M word.

Luke


Re: multisub.arity?

2005-09-06 Thread Damian Conway

H. The arity of a given multi might be 3 or 4 or 5.

If *only* there were a way to return a single value that was simultaneously 
any of 3 or 4 or 5.


Oh, wait a minute...

Damian



Re: multisub.arity?

2005-09-06 Thread Luke Palmer
On 9/3/05, Damian Conway [EMAIL PROTECTED] wrote:
 H. The arity of a given multi might be 3 or 4 or 5.
 
 If *only* there were a way to return a single value that was simultaneously
 any of 3 or 4 or 5.
 
 Oh, wait a minute...

Well, we'd better document that pretty damn well then, and provide
min_arity and max_arity, too.   This is one of those places where
Yuval is spot on about autothreading being evil.  This is also one of
those places where I am spot on about Junctive logic being evil.

It looks like returning a junction is the dwimmiest thing we can do here:

given code.arity {
when 1 { code(1) }
when 2 { code(1,2) }
}

So if code is a multimethod that has variants that take two
parameters or three parameters, great, we call it with (1,2), which
will succeed.  And if it has variants that take one parameter or three
parameters, great, we call it with (1), which will succeed.  And if it
has variants that take one parameter or two parameters, um..., great,
we call it with (1), which will succeed.

In that last case though, this is not equivalent to the above:

given code.arity {
when 2 { code(1,2) }
when 1 { code(1) }
}

That may be a little... surprising.  Still, it's fixed to succeed
either way, so that's probably okay, right?

But let's do a little thinking here.  You're asking a code reference
for its arity.  It's pretty likely, that unless you are doing
dwimminess calculations (which aren't that uncommon, especially in
Damian's modules), that you have no idea what the arguments are
either.  An example of a function that uses arity is map.

sub map (code, [EMAIL PROTECTED]) {
gather {
my @args = @list.splice(0, code.arity);
take code([EMAIL PROTECTED]);
}
}

In the best case (depending on our decision), this fails with can't
assign a junction to an array.  In the worst case, it autothreads
over splice, returning a junction of lists, makes @args a junction of
lists, and then returns a list of junctions for each arity the
multimethod could have taken on.  I don't think that's correct... at
all.   The correct way to have written that function is:

sub map (code, [EMAIL PROTECTED]) {
gather {
my @args = @list.splice(0, min(grep { ?$_ } code.arity.states));
take code([EMAIL PROTECTED]);
}
}

Not quite so friendly anymore.  In order to use this, we had to access
the states of the junction explicitly, which pretty much killed the
advantage of it being a junction.

Junctions are logical travesty, and it seems to me that they cease to
be useful in all but the situations where the coder knows
*everything*.

But I still like them.

Here's how I'm thinking they should work.  This is a minimalistic
approach: that is, I'm defining them in the safest and most limited
way I can, and adding useful cases, instead of defining them in the
richest and most general way possible and forbidding cases that are
deemed unsafe.

Throw out all your notions about how Junctions work.  We're building
from scratch.

Things that come on the right side of smart match do a role called
Pattern, which looks like this:

role Pattern {
method match(Any -- Bool) {...}
}

Among the things that do pattern are Numbers, Strings, Arrays, ...
(equivalence); Types, Sets, Hashes (membership); Bools, Closures
(truth); and Junctions (pattern grep).  That is, a Junction is just a
collection of Patterns together with a logical operation.  It, in
turn, is a pattern that can be smart-matched against.  Therefore, we
sidestep the issue of the existence of junctions making every ordered
set have exactly one element[1]. because there is nothing illogical
against testing against a pattern.  You can also safely pass it to
functions, and they can use it in their smart matches, and everything
is dandy.

That's it for the base formulation.  A junction is just a pattern, and
it makes no sense to use it outside of the smart-match operator.

But that means that we have to change our idioms:

if $x == 1 | 2 | 3   {...}
# becomes
if $x ~~ 1 | 2 | 3   {...}# not so bad

if $x  $a | $b  {...}
# becomes
if ($x ~~ { $_  $a } | { $_  $b }) {...}  # eeeyuck
if $x  $a || $x  $b {...}  # back to square one

# from E06
if any(@newvals)  any(@oldvals) {
say Already seen at least one smaller value;
}
# becomes
if (grep { my $old = $_; grep { $_  $old } @newvals } @oldvals) {
say I don't remember what I was going to say because the
condition took so long to type
}

So, that sucks.  But I'm beginning to wonder whether we're really
stuck there.  The two yucky examples above can be rewritten, once we
take advantage of some nice properties of orderings:

if $x  max($a, $b) {...}
if min(@newvals)  min(@oldvals) {...}

But that's a solution to the specific comparison problems, not the
general threaded logic problem.

Yeah... so, that's 

Re: multisub.arity?

2005-09-06 Thread Juerd
Luke Palmer skribis 2005-09-06 13:28 (+):
 Well, we'd better document that pretty damn well then, and provide
 min_arity and max_arity, too.

Won't junctions do Array, then? I think foo.arity.max would be very
intuitive, and likewise, for @foo.arity { ... }


Juerd
-- 
http://convolution.nl/maak_juerd_blij.html
http://convolution.nl/make_juerd_happy.html 
http://convolution.nl/gajigu_juerd_n.html



Re: multisub.arity?

2005-09-06 Thread Yuval Kogman
On Tue, Sep 06, 2005 at 13:28:24 +, Luke Palmer wrote:

This should still work:

 sub map (code, [EMAIL PROTECTED]) {
 gather {
 my @args = @list.splice(0, code.arity);
 take code([EMAIL PROTECTED]);
 }
 }

multi sub foo ( ... ) { ... } 
multi sub foo ( ... ) { ... }

my @mapped = map foo ...;

I think this is inconsistent.

There is another option though:

sub map (code, [EMAIL PROTECTED]) {
gather {
take code.mutably_bind_some(@list); # removes stuff
# from @list
}
}

The code object can then look for suitable multimethod alternatives
for the arguments in question, avoid that alltogether, dispatch
based on the arity of the first alternative, dispatch based on the
arity of the most general alternative, or whatever.

I would be careful though, and only pass singly bindable, non slurpy
code refs into map in my code, in which case i'd expect
'mutably_bind_some(@list)' to be along these lines:

method mutably_bind_some ([EMAIL PROTECTED] is rw) {
my @bound_params = map { pop @params } 1 .. $?SELF.arity;
$?SELF.bind_params(@bound_params);
}

-- 
 ()  Yuval Kogman [EMAIL PROTECTED] 0xEBD27418  perl hacker 
 /\  kung foo master: /me supports the ASCII Ribbon Campaign: neeyah!!!



pgpZ6GyiTREuw.pgp
Description: PGP signature


Re: multisub.arity?

2005-09-06 Thread Austin Hastings

On a related note:

Suppose I have a function with a non-obvious arity: I might, in a 
desperate attempt to find billable hours, describe the arity as a trait:


 sub sandwich($bread, $meat, $cheese, $condiment1, $qty1, ...)
 does arity ({ 3 + 2 * any(1..Inf); });

That's cougheasy enough for trivial cases like this, but is there a 
way to use Cassuming for the more difficult cases?


Specifically, and obviously, printf-and-friends:

 my example := printf.assuming(format = %s %s %n\n);
 say example.arity();

The obvious output is any(1..Inf), since who's going to code the arity 
function?


But:

1. Is it possible to code an arity trait as a run-time block? (I assume yes)

2. Could this, or any, trait take advantage of assumed parameters? If 
so, how?


(Of course, after the arity function is written, it seems obvious to die 
unless the current function's arity is le the number of arguments...)


=Austin





Re: multisub.arity?

2005-09-06 Thread Damian Conway

Luke wrote:

 Well, we'd better document that [junctive arity values] pretty damn
 well then, and provide min_arity and max_arity, too.

Unnecessary. The Cmax and Cmin builtins should be overloaded to Just
Work on junctive values:

if min code.arity  2 {...}


 This is one of those places where Yuval is spot on about autothreading
 being evil. This is also one of those places where I am spot on about
 Junctive logic being evil.

No. Neither autothreading nor junctive logic is evil. They're just
different. I know that many people can't tell the difference between
evil and different, but you two are smart enough to be able to.


 It looks like returning a junction is the dwimmiest thing we can do here:

 given code.arity {
 when 1 { code(1) }
 when 2 { code(1,2) }
 }

 So if code is a multimethod that has variants that take two
 parameters or three parameters, great, we call it with (1,2), which
 will succeed.  And if it has variants that take one parameter or three
 parameters, great, we call it with (1), which will succeed.  And if it
 has variants that take one parameter or two parameters, um..., great,
 we call it with (1), which will succeed.

 In that last case though, this is not equivalent to the above:

 given code.arity {
 when 2 { code(1,2) }
 when 1 { code(1) }
 }

 That may be a little... surprising.  Still, it's fixed to succeed
 either way, so that's probably okay, right?

It's not surprising at all. The order of Cwhen tests (usually) matters,
because a series of Cwhen statements (usually) short-circuits.


 But let's do a little thinking here.  You're asking a code reference
 for its arity.  It's pretty likely, that unless you are doing
 dwimminess calculations (which aren't that uncommon, especially in
 Damian's modules), that you have no idea what the arguments are
 either.  An example of a function that uses arity is map.

 sub map (code, [EMAIL PROTECTED]) {
 gather {
 my @args = @list.splice(0, code.arity);
 take code([EMAIL PROTECTED]);
 }
 }

 In the best case (depending on our decision), this fails with can't
 assign a junction to an array.  In the worst case, it autothreads
 over splice, returning a junction of lists, makes @args a junction of
 lists, and then returns a list of junctions for each arity the
 multimethod could have taken on.  I don't think that's correct... at
 all.   The correct way to have written that function is:

 sub map (code, [EMAIL PROTECTED]) {
 gather {
 my @args
 = @list.splice(0, min(grep { ?$_ } code.arity.states));

BTW, that should be code.arity.values, not code.arity.states.


 take code([EMAIL PROTECTED]);
 }
 }

 Not quite so friendly anymore.

Only because you're doing it the unfriendly way. Instead of, for example:

  sub map (code, [EMAIL PROTECTED]) {
  gather {
  my @args = @list.splice(0, min code.arity);
  take code([EMAIL PROTECTED]);
  }
  }

which is perfectly friendly, and also clearer. Or, perhaps more usefully, a 
multi should be illegal as a map block:


  sub map (code, [EMAIL PROTECTED]) {
  croak Can't use multi as map block if code.arity.values  1;
  gather {
  my @args = @list.splice(0, code.arity);
  take code([EMAIL PROTECTED]);
  }
  }



 Junctions are logical travesty,

Well, that's very emotive, but I don't believe it's either a useful or an 
accurate characterization. I would agree that junctions can be logically 
*sophisticated*, but then I'd argue that *all* programming constructs are that.



 and it seems to me that they cease to be useful in all but the
 situations where the coder knows *everything*.

What does that mean, exactly? How can anyone *ever* write sensible code
without knowing what kind of values they're processing?


 But I still like them.

 Here's how I'm thinking they should work.  This is a minimalistic
 approach: that is, I'm defining them in the safest and most limited
 way I can, and adding useful cases, instead of defining them in the
 richest and most general way possible and forbidding cases that are
 deemed unsafe.

 Throw out all your notions about how Junctions work.  We're building
 from scratch.

 Things that come on the right side of smart match do a role called
 Pattern, which looks like this:

 role Pattern {
 method match(Any -- Bool) {...}
 }

 Among the things that do pattern are Numbers, Strings, Arrays, ...
 (equivalence); Types, Sets, Hashes (membership); Bools, Closures
 (truth); and Junctions (pattern grep).  That is, a Junction is just a
 collection of Patterns together with a logical operation.  It, in
 turn, is a pattern that can be smart-matched against.  Therefore, we
 sidestep the issue of the existence of junctions making every ordered
 set have exactly one element[1]. because there is nothing 

Re: multisub.arity?

2005-09-03 Thread Yuval Kogman
On Fri, Sep 02, 2005 at 17:56:39 +0200, Ingo Blechschmidt wrote:
 Hi,
 
 multi foo ($a) {...}
 multi foo ($a, $b) {...}
 
 say foo.arity;
 # die? warn and return 0? warn and return undef? return 1|2?

A multi sub is a collection of variants, so it doesn't have arity,
each variant has arity.

I'd say it 'fail's.

To get the arity you must tell it which variant yyou mean, either by
providing enough of the prototype, eg

foo(Any).arity   vs   foo(Any, Any).arity

-- 
 ()  Yuval Kogman [EMAIL PROTECTED] 0xEBD27418  perl hacker 
 /\  kung foo master: : neeyah!



pgpJITcejqLNO.pgp
Description: PGP signature


Re: multisub.arity?

2005-09-03 Thread Stuart Cook
On 03/09/05, Yuval Kogman [EMAIL PROTECTED] wrote:
 A multi sub is a collection of variants, so it doesn't have arity,
 each variant has arity.
 
 I'd say it 'fail's.

But if the reason you're calling `foo.arity` is to answer the
question Can I call this sub with three arguments? then that kind of
behaviour isn't going to help very much.

Which leads me to believe that instead of writing

  if foo.arity == 3 { ... }

you should probably be writing something like this:

  if foo.accepts(3) { ... }

Implying that you could also write:

  if foo.accepts(:pos(1..3) :namedfoo bar :code) { ... }

None of this really answers the question What should foo.arity
return?, but my point is that most of the time you probably shouldn't
be calling it yourself anyway.  Better to tell the sub what you
actually intend to do, and let it make up its own mind (via its
Signature(s)).

 To get the arity you must tell it which variant yyou mean, either by
 providing enough of the prototype, eg
 
 foo(Any).arity   vs   foo(Any, Any).arity

Unfortunately, that particular syntax is going to end up *calling*
foo (unless of course you make .arity a special form).


Stuart


Re: multisub.arity?

2005-09-03 Thread Yuval Kogman
On Sun, Sep 04, 2005 at 00:27:39 +1000, Stuart Cook wrote:
   if foo.accepts(:pos(1..3) :namedfoo bar :code) { ... }

I prefer this api... Arity is ambiguous will multiply variadic args.
We have any number of positionals, nameds, and zero, one or two
slurpies.

 None of this really answers the question What should foo.arity
 return?, but my point is that most of the time you probably shouldn't
 be calling it yourself anyway.  Better to tell the sub what you
 actually intend to do, and let it make up its own mind (via its
 Signature(s)).

Yep

  To get the arity you must tell it which variant yyou mean, either by
  providing enough of the prototype, eg
  
  foo(Any).arity   vs   foo(Any, Any).arity
 
 Unfortunately, that particular syntax is going to end up *calling*
 foo (unless of course you make .arity a special form).

There was a syntax to disambiguate multis to .assuming... I meant
that.

-- 
 ()  Yuval Kogman [EMAIL PROTECTED] 0xEBD27418  perl hacker 
 /\  kung foo master: /me sushi-spin-kicks : neeyah



pgpxBzmLCxxY1.pgp
Description: PGP signature


Re: multisub.arity?

2005-09-03 Thread Luke Palmer
On 9/3/05, Stuart Cook [EMAIL PROTECTED] wrote:
 On 03/09/05, Yuval Kogman [EMAIL PROTECTED] wrote:
  A multi sub is a collection of variants, so it doesn't have arity,
  each variant has arity.
 
  I'd say it 'fail's.
 
 But if the reason you're calling `foo.arity` is to answer the
 question Can I call this sub with three arguments? then that kind of
 behaviour isn't going to help very much.
 
 Which leads me to believe that instead of writing
 
   if foo.arity == 3 { ... }
 
 you should probably be writing something like this:
 
   if foo.accepts(3) { ... }

That's a nice reformulation.  However, .arity is still important.  But
maybe .arity doesn't exist, and all you get are .accepts, .min_arity,
and .max_arity.  After all, for has to know how many things to take
off of the list, and doing:

my @pass;
given ({ foo.accepts($_) }) {
when 1 { @pass = @args.shift(0,1) }
when 2 { @pass = @args.splice(0,2) }
...
}

Is unacceptable.  But *the* arity of a function in Perl is rather ill-defined.

(As a matter of fact, I use the existence numeric casing to determine
when a language is not general enough in a particular area;  C++ had
to do numeric casing to implement typelists, Haskell has to do numeric
casing to implement variadic functions and lifts, etc.   So far, I've
never had to do it in Perl. :-)

Luke


Re: multisub.arity?

2005-09-02 Thread Larry Wall
On Fri, Sep 02, 2005 at 05:56:39PM +0200, Ingo Blechschmidt wrote:
: Hi,
: 
: multi foo ($a) {...}
: multi foo ($a, $b) {...}
: 
: say foo.arity;
: # die? warn and return 0? warn and return undef? return 1|2?

How 'bout undef but 1..2?  :-)

Larry