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 C<max> and C<min> 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 C<when> tests (usually) matters,
because a series of C<when> 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 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

Yes. Bad. Because now I can't specify that I specifically want to test with C<==> or C<eq> or my new C<^%$!> operator.


>     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 what I think about junctions.  This is definitely a
> tentative proposal, so if there are cases where junctions in their
> current state make a certain problem a lot easier (and I mean
> conceptual changes, not minor syntactic issues), then I want to hear
> them so we can try to expand this proposal to include that
> functionality.  Also remember about hyper-argument foo(>>1,2,3<<)
> which has your autothreading base covered.

Otherwise hard things that junctions make a lot easier:

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


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


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


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


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


    sub roots ($A, $B, $C) {
        return (-$B + (1|-1)*sqrt($B**2 - 4*$A*$C) ) / 2*$A;
    }


    &constraints := all gather {
        # various config tests resulting in varieties of...
        take sub {...};
    }
    # and later...
    if constraints($value) {...}



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

No. This is a simple fallacy. You're ignoring the inherent logical
asymmetry of the implicit alternative. Consider:

    Luke is no smarter than (Luke or a rock).
    (Luke or a rock) is no smarter than a rock.

    Therefore Luke is no smarter than a rock.

Clearly a false conclusion. ;-)

But the logical error is made clearer when the distribution is made explicit:

    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):

    Luke is no smarter than Luke
                                      a rock is no smarter than a rock.

But now the remaining assertions support *no* new conclusion.


Damian

Reply via email to