Re: multisub.arity?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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