Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

.map/.reduce with larger arity

5 views
Skip to first unread message

Moritz Lenz

unread,
Mar 8, 2009, 4:36:17 PM3/8/09
to perl6-l...@perl.org
Currently the spec says:

C<map> returns a lazily evaluated list which is comprised of
the return value of the expression, evaluated once for every
one of the C<@values> that are passed in.

But both pugs and rakudo respect the arity of the code ref passed to it,
so that (1..6).map({$^a + $^b + $^c}) returns the list (6, 15), which is
very nice and very DWIM'my.

But it opens the question what should happen if there is a number of
items in the list that's not easily divisible by the arity - should the
rest just be padded with undef's? or just ignored? Or fail() with a
friendly error message?

I don't really mind either way, just want to test and implement it
correctly.

The same question also arises for "magical" List.reduce and similar methods.

Cheers,
Moritz

Larry Wall

unread,
Mar 9, 2009, 12:31:19 AM3/9/09
to perl...@perl.org, perl6-l...@perl.org
On Sun, Mar 08, 2009 at 09:36:17PM +0100, Moritz Lenz wrote:
: Currently the spec says:
:
: C<map> returns a lazily evaluated list which is comprised of
: the return value of the expression, evaluated once for every
: one of the C<@values> that are passed in.
:
: But both pugs and rakudo respect the arity of the code ref passed to it,
: so that (1..6).map({$^a + $^b + $^c}) returns the list (6, 15), which is
: very nice and very DWIM'my.
:
: But it opens the question what should happen if there is a number of
: items in the list that's not easily divisible by the arity - should the
: rest just be padded with undef's? or just ignored? Or fail() with a
: friendly error message?
:
: I don't really mind either way, just want to test and implement it
: correctly.

I think the basic rule has to be simply can the signature bind to
the remaining arguments. If not, we get a warning on unused arguments.
We can mark arguments as optional if that's what we mean. About the
only thing I see to decide is whether the 2nd and subsequent placeholders
consider themselves optional parameters. Is it better to get a single warning
earlier when some arguments go unused, or is it better to assume the
subsequent code can handle undefined paramets, with the likely result
of more undefined access warnings later on? My gut feeling is that
placeholder variables probably should not be considered optional; in
most cases a non-divisible number of arguments indicates a logic error
in the program, and an earlier message is better, even at the expense
of thowing away some (possibly valid) partial data. Especially since
we do have a way to indicate that partial data is acceptable:

-> $a, $b?, $c? { $a + ($b//0) + ($c//0) }

Larry

Patrick R. Michaud

unread,
Mar 9, 2009, 12:38:29 PM3/9/09
to perl...@perl.org, perl6-l...@perl.org
On Sun, Mar 08, 2009 at 09:31:19PM -0700, Larry Wall wrote:
> On Sun, Mar 08, 2009 at 09:36:17PM +0100, Moritz Lenz wrote:
> : But both pugs and rakudo respect the arity of the code ref passed to it,
> : so that (1..6).map({$^a + $^b + $^c}) returns the list (6, 15), which is
> : very nice and very DWIM'my.
> :
> : But it opens the question what should happen if there is a number of
> : items in the list that's not easily divisible by the arity - should the
> : rest just be padded with undef's? or just ignored? Or fail() with a
> : friendly error message?
>
> I think the basic rule has to be simply can the signature bind to
> the remaining arguments. If not, we get a warning on unused arguments.
> We can mark arguments as optional if that's what we mean.
> [...]

> My gut feeling is that
> placeholder variables probably should not be considered optional; in
> most cases a non-divisible number of arguments indicates a logic error
> in the program, and an earlier message is better, even at the expense
> of thowing away some (possibly valid) partial data. Especially since
> we do have a way to indicate that partial data is acceptable:
>
> -> $a, $b?, $c? { $a + ($b//0) + ($c//0) }

Presumably whatever we decide for C<map()> also applies to C<for>, yes?

for 1..4 -> $a, $b, $c { ... } # error
for 1..4 -> $a, $b, $c? { ... } # error
for 1..4 -> $a, $b?, $c? { ... } # ok

Pm

Daniel Ruoso

unread,
Mar 9, 2009, 1:40:43 PM3/9/09
to Larry Wall, perl...@perl.org, perl6-l...@perl.org
Em Dom, 2009-03-08 às 21:31 -0700, Larry Wall escreveu:
> I think the basic rule has to be simply can the signature bind to
> the remaining arguments. If not, we get a warning on unused arguments.

Just to put here an idea I sent on irc...

What if Signature.ACCEPTS set $/ with the matched arguments?

That way we can both know how many arguments the Signature can receive
as well as allow us to use the match as the capture to that call...

... $capture ~~ $signature ...;
my $args_matched = @($/).elems;
&code.(|$/);

daniel

Larry Wall

unread,
Mar 9, 2009, 7:09:59 PM3/9/09
to perl...@perl.org, perl6-l...@perl.org
On Mon, Mar 09, 2009 at 11:38:29AM -0500, Patrick R. Michaud wrote:

Yes, the only difference between C<for> and C<map> is that you can
only use C<for> at the start of a statement. But we're more liberal
about where statements are expected in Perl 6, so you can say things
like:

my @results = do for @list -> $x {...};
my @results = (for @list -> $x {...});

and either of those is equivalent to:

my @results = map -> $x {...}, @list;

I also Officially Don't Care if you use map in a void context. :)

Larry

Martin D Kealey

unread,
Mar 10, 2009, 2:46:51 AM3/10/09
to Larry Wall, perl...@perl.org, perl6-l...@perl.org
On Mon, 9 Mar 2009, Larry Wall wrote:

> the only difference between C<for> and C<map> is that you can only use
> C<for> at the start of a statement. But we're more liberal about where
> statements are expected in Perl 6, so you can say things like:
>
> my @results = do for @list -> $x {...};
> my @results = (for @list -> $x {...});
>
> and either of those is equivalent to:
>
> my @results = map -> $x {...}, @list;
>
> I also Officially Don't Care if you use map in a void context. :)

(Good.)

<tongue-in-cheek> Maybe we should just treat "map" as a synonym for "for". </tongue-in-cheek>

I'd like to be able to use grep, map, etc in a currying fashion. Can I do:

my &square_list := -> $x { $x * $x }.map();

And if so, what is the signature of &square_list ?

Maybe that's why there's a difference between "for" and "map"

@list = @array.map(&code);

&iterator = &code.for($signature);
@list = iterator(@list);

But I suspect they should logically be the other way around:

&iterator = &code.map($signature);
@list = iterator(@list);

@list = @array.for(&code);

-Martin

Daniel Ruoso

unread,
Mar 10, 2009, 4:57:28 PM3/10/09
to Larry Wall, perl...@perl.org, perl6-l...@perl.org
Em Seg, 2009-03-09 às 12:24 -0700, Larry Wall escreveu:
> On Mon, Mar 09, 2009 at 02:40:43PM -0300, Daniel Ruoso wrote:
> : ... $capture ~~ $signature ...;

> : my $args_matched = @($/).elems;
> : &code.(|$/);
> That API still would not tell the match whether signature must match the
> entire capture (what you want for normal binding) or can stop part way
> (what you want for map and friends).

if $capture ~~ $signature :partial {
$capture = $<remaining>;
&code.(|@($/));
}

daniel

Leon Timmermans

unread,
Mar 25, 2009, 6:20:40 PM3/25/09
to perl6-l...@perl.org
On Tue, Mar 10, 2009 at 12:09 AM, Larry Wall <la...@wall.org> wrote:
>
> Yes, the only difference between C<for> and C<map> is that you can
> only use C<for> at the start of a statement.  But we're more liberal
> about where statements are expected in Perl 6, so you can say things
> like:
>
>    my @results = do for @list -> $x {...};
>    my @results = (for @list -> $x {...});
>
> and either of those is equivalent to:
>
>    my @results = map -> $x {...}, @list;
>
> I also Officially Don't Care if you use map in a void context. :)
>
> Larry
>

I would propose there to be one difference between for an map: map
should bind its arguments read-only, for should bind them read-write.
That would make at least one bad practice an error.

Leon

Moritz Lenz

unread,
Mar 25, 2009, 7:38:37 PM3/25/09
to Leon Timmermans, perl6-l...@perl.org
Leon Timmermans wrote:

> I would propose there to be one difference between for an map: map
> should bind its arguments read-only, for should bind them read-write.
> That would make at least one bad practice an error.

That sounds very impractical, because the ro/rw distinction is part of
the signature, not of the capture.

Cheers,
Moritz

Mark J. Reed

unread,
Mar 25, 2009, 7:23:24 PM3/25/09
to Leon Timmermans, perl6-l...@perl.org
On Wed, Mar 25, 2009 at 6:20 PM, Leon Timmermans <faw...@gmail.com> wrote:
> I would propose there to be one difference between for an map: map
> should bind its arguments read-only, for should bind them read-write.
> That would make at least one bad practice an error.

Why is r/w map a bad practice if r/w for is not?

Do you look at Perl's "map" and think "A-ha! The map operation is a
functional programming idiom, therefore it must be side-effect free!"?
Because that view doesn't feel terribly Perlish to me.

While I mostly use both map and for in readonly mode, I've been known
to use map for quickie in place mutations, and not necessarily in void
context:

my @prev = map { $_++ } @values;

I'm not arguing for the binding to default to rw - you can always use
"is rw" when needed. I just don't see any reason why the default
binding behavior of map and for should be different.

--
Mark J. Reed <mark...@gmail.com>

Moritz Lenz

unread,
Mar 25, 2009, 7:36:29 PM3/25/09
to Leon Timmermans, perl6-l...@perl.org
Leon Timmermans wrote:

> I would propose there to be one difference between for an map: map
> should bind its arguments read-only, for should bind them read-write.
> That would make at least one bad practice an error.

That sounds very impractical, because the ro/rw distinction is part of

0 new messages