On 10/5/05, Damian Conway <[EMAIL PROTECTED]> wrote:
> Luke wrote:
>  > I'm just wondering why you feel that we need to be so careful.
>
> Because I can think of at least three reasonable and useful default behaviours
> for zipping lists of differing lengths:
>
>      # Minimal (stop at first exhausted list)...
>      for @names ¥ @addresses -> $name, $addr {
>          ...
>      }
>
>
>      # Maximal (insert undefs for exhausted lists)...
>      for @finishers ¥ (10..1 :by(-1))  -> $name, $score {
>          $score err next;
>          ...
>      }
>
>
>      # Congealed (ignore exhausted lists)...
>      for @queue1 ¥ @queue2 -> $server {
>          ...
>      }
>
> Which means that there will be people who expect each of those to *be* the
> default behaviour for unbalanced lists.

Perhaps that makes sense.  That certainly makes sense for other kinds
of constructs.  Something makes me think that this is a little
different.  Whenever somebody asks what "Y" is on #perl6, and I tell
them that it interleaves two lists, a follow-up question is *always*
"what does it do when the lists are unbalanced."  Now, that may just
be a behavior of #perl6ers, but I'm extrapolating.  It means that
there isn't an assumption, and if they weren't #perl6ers, they'd RTFM
about it.

When I learned Haskell and saw zip, I asked the very same question[1].
 I was about as comfortable writing Haskell at that point as beginning
programmers are with writing Perl, but it still took me about ten
seconds to write a test program to find out.  The rest of Perl doesn't
trade a reasonable default behavior for an error, even if it *might*
be surprising the first time you use it.  It doesn't take people long
to discover that kind of error and never make that mistake again.

If we make zip return a list of tuples rather than an interleaved
list, we could eliminate the final 1/3 of those errors above using the
typechecker.  That would make the for look like this:

    for @a Y @b -> ($a, $b) {...}

An important property of that is the well-typedness of the construct. 
With the current zip semantics:

    my A @a;
    my B @b;
    for @a Y @b -> $a, $b {
        # $a has type A (+) B
        # $b has type A (+) B
    }

With tuple:

    my A @a;
    my B @b;
    for @a Y @b -> ($a, $b) {
        # $a has type A
        # $b has type B
    }

Which is more correct.  No... it's just correct, no superlative
needed.  It also keeps things like this from happening:

    for @a Y @b -> $a, $b {
        say "$a ; $b"
    }
    # a1 b1
    # a2 b2
    # a3 b3
    # ...

"Oh, I need a count," says the user:

    for @a Y @b Y 0... -> $a, $b {  # oops, forgot to add $index
        say "$a ; $b"
    }
    # a1 b1
    # 0  a2
    # b2 1
    # ...

Luke

[1] But I didn't need to.  The signature told me everything:

    zip :: [a] -> [b] -> [(a,b)]

It *has* to stop at the shortest one, because it has no idea how to
create a "b" unless I tell it one.  If it took the longest, the
signature would have looked like:

    zip :: [a] -> [b] -> [(Maybe a, Maybe b)]

Anyway, that's just more of the usual Haskell praise.

Reply via email to