map { $_ => $_ } @foo

23 views
Skip to first unread message

Autrijus Tang

unread,
Apr 24, 2005, 2:13:26 PM4/24/05
to perl6-l...@perl.org
A while ago I posted a conflict between a block containing a pair
constructor, vs. a hash constructor:

map { $_ => $_ } @foo;

Larry suggested that to keep it from being collapsed, we somehow
augment toplevel AST:

map { $_ => $_; } @foo;
map { +($_ => $_) } @foo;

But here is a new idea: Since the parser knows that the bare block is
followed by no trailing comma, how about we using it as a disambiguating
device, and define that it never collapses?

map { $_ => $_ } @foo; # closure
map { $_ => $_ }, @foo; # hash

And maybe it can be extended over adverbial blocks, too:

@foo.map:{ $_ => $_ }; # closure

Also as control structure body, just for consistency's sake:

for @foo { $^x => $^y };

Is it a sane approach? I have just tentatively implemented it as r2305
if people would like to experiment with this proposal.

Thanks,
/Autrijus/

Larry Wall

unread,
Apr 24, 2005, 7:39:04 PM4/24/05
to perl6-l...@perl.org
On Mon, Apr 25, 2005 at 02:13:26AM +0800, Autrijus Tang wrote:
: A while ago I posted a conflict between a block containing a pair

: constructor, vs. a hash constructor:
:
: map { $_ => $_ } @foo;
:
: Larry suggested that to keep it from being collapsed, we somehow
: augment toplevel AST:
:
: map { $_ => $_; } @foo;
: map { +($_ => $_) } @foo;

Uh, I'm not sure what + would return for a Pair, but I'm pretty sure it's
not a pair. A little P5ism sneaking in there? :-)

: But here is a new idea: Since the parser knows that the bare block is


: followed by no trailing comma, how about we using it as a disambiguating
: device, and define that it never collapses?
:
: map { $_ => $_ } @foo; # closure
: map { $_ => $_ }, @foo; # hash

A block can be arbitrarily long. I worry about disambiguating it by
something could come lines later. It's the /x problem all over again.
Plus, I think many folks would rather think of the closure comma as
optional rather than mandatorily missing. Besides, if they can't
keep the {...} straight, they're not gonna keep the comma straight either.

: And maybe it can be extended over adverbial blocks, too:


:
: @foo.map:{ $_ => $_ }; # closure
:
: Also as control structure body, just for consistency's sake:
:
: for @foo { $^x => $^y };
:
: Is it a sane approach? I have just tentatively implemented it as r2305
: if people would like to experiment with this proposal.

I really think for clarity it has to be disambiguated by either
something syntactic on the front or something semantic at the top level.
It's probably pretty easy to catch the error of saying

map { $_ => $_ } @foo;

when you mean

map { hash $_ => $_ } @foo;

or

map { list $_ => $_ } @foo;

because map wants a closure as its first argument, not a hash. I still
kinda like the rule that it's a hash if the top-level looks like some
kind of list of pairs. It optimizes for the common case. Closures
returning pairs are a rarity.

Larry

Darren Duncan

unread,
Apr 24, 2005, 9:14:35 PM4/24/05
to perl6-l...@perl.org
At 4:39 PM -0700 4/24/05, Larry Wall wrote:
>On Mon, Apr 25, 2005 at 02:13:26AM +0800, Autrijus Tang wrote:
>: A while ago I posted a conflict between a block containing a pair
>: constructor, vs. a hash constructor:
>:
>: map { $_ => $_ } @foo;
>
>: And maybe it can be extended over adverbial blocks, too:
>:
>: @foo.map:{ $_ => $_ }; # closure

Why not just always use the ':' when you are giving a block. The
block is essentially an adverb for a map|grep|sort anyway. Whereas,
no ':' means its a hash-ref. (Presumably each of map|grep|sort will
have a reasonable default adverb if no ':{}' is given.)

>I really think for clarity it has to be disambiguated by either
>something syntactic on the front or something semantic at the top level.

I agree. See my previous paragraph for an example.

>I still
>kinda like the rule that it's a hash if the top-level looks like some
>kind of list of pairs. It optimizes for the common case.

I agree.

>Closures
>returning pairs are a rarity.
>Larry

This is beside the point but ...

Perhaps one of the new Perl 6 features makes this unnecessary, but I
often found myself doing just that when I wanted an effective method
to test multiple times if an element is in an array, like this:

my %foo = map:{ ( $_ => 1 ) } @bar;
if( %foo{'abc'} ) ...
if( %foo{'def'} ) ...
if( %foo{'zrs'} ) ...

That closure is returning a pair for each array element.

-- Darren Duncan

Larry Wall

unread,
Apr 24, 2005, 9:50:03 PM4/24/05
to perl6-l...@perl.org
On Sun, Apr 24, 2005 at 06:14:35PM -0700, Darren Duncan wrote:
: At 4:39 PM -0700 4/24/05, Larry Wall wrote:
: >On Mon, Apr 25, 2005 at 02:13:26AM +0800, Autrijus Tang wrote:
: >: A while ago I posted a conflict between a block containing a pair
: >: constructor, vs. a hash constructor:
: >:
: >: map { $_ => $_ } @foo;
: >
: >: And maybe it can be extended over adverbial blocks, too:
: >:
: >: @foo.map:{ $_ => $_ }; # closure
:
: Why not just always use the ':' when you are giving a block. The
: block is essentially an adverb for a map|grep|sort anyway. Whereas,
: no ':' means its a hash-ref. (Presumably each of map|grep|sort will
: have a reasonable default adverb if no ':{}' is given.)

There are lots of blocks that shouldn't take colons.

: >I really think for clarity it has to be disambiguated by either


: >something syntactic on the front or something semantic at the top level.
:
: I agree. See my previous paragraph for an example.
:
: >I still
: >kinda like the rule that it's a hash if the top-level looks like some
: >kind of list of pairs. It optimizes for the common case.
:
: I agree.
:
: >Closures
: >returning pairs are a rarity.
: >Larry
:
: This is beside the point but ...
:
: Perhaps one of the new Perl 6 features makes this unnecessary, but I
: often found myself doing just that when I wanted an effective method
: to test multiple times if an element is in an array, like this:
:
: my %foo = map:{ ( $_ => 1 ) } @bar;
: if( %foo{'abc'} ) ...
: if( %foo{'def'} ) ...
: if( %foo{'zrs'} ) ...
:
: That closure is returning a pair for each array element.

How 'bout:

%foo{@bar} »=« 1;

That seems a lot clearer to me. If you don't like hyper, how about

%foo{@bar} = (1..2:by(0));

:-)

Larry

Juerd

unread,
Apr 25, 2005, 2:49:13 AM4/25/05
to perl6-l...@perl.org
Larry Wall skribis 2005-04-24 18:50 (-0700):

> %foo{@bar} = (1..2:by(0));


%foo{@bar} = 1 xx Inf;

%foo{@bar} = 1 xx @bar;


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

Autrijus Tang

unread,
Apr 25, 2005, 4:52:08 AM4/25/05
to perl6-l...@perl.org
On Sun, Apr 24, 2005 at 04:39:04PM -0700, Larry Wall wrote:
> : Larry suggested that to keep it from being collapsed, we somehow
> : augment toplevel AST:
> :
> : map { $_ => $_; } @foo;
> : map { +($_ => $_) } @foo;
>
> Uh, I'm not sure what + would return for a Pair, but I'm pretty sure it's
> not a pair. A little P5ism sneaking in there? :-)

Aye, indeed. :-)

> : But here is a new idea: Since the parser knows that the bare block is
> : followed by no trailing comma, how about we using it as a disambiguating
> : device, and define that it never collapses?
> :
> : map { $_ => $_ } @foo; # closure
> : map { $_ => $_ }, @foo; # hash
>
> A block can be arbitrarily long. I worry about disambiguating it by
> something could come lines later. It's the /x problem all over again.
> Plus, I think many folks would rather think of the closure comma as
> optional rather than mandatorily missing. Besides, if they can't
> keep the {...} straight, they're not gonna keep the comma straight either.

Okay, I concur. r2319 now renders the trailing comma / adverbial colon
orthogonal to closure collapsing again; I have also implemented your
top-level-expression rule from an easlier thread. So to disambiguate,
one has to write this now:

map { $_ => $_; } @foo;

This works too:

map { ;$_ => $_ } @foo;

But () is still only a grouper, so this won't do:

map { ($_ => $_) } @foo;

Does this make sense?

Thanks,
/Autrijus/

Thomas Sandlaß

unread,
Apr 26, 2005, 12:43:44 PM4/26/05
to Autrijus Tang, perl6-l...@perl.org
Autrijus Tang wrote:
> map { $_ => $_; } @foo;
>
> This works too:
>
> map { ;$_ => $_ } @foo;
>
> But () is still only a grouper, so this won't do:
>
> map { ($_ => $_) } @foo;
>
> Does this make sense?

A lot! BTW, is it possible to distinguish methods and subs
from the toplevel, too? That little inference might help
to solve the topic versus invocant problem by not requiring
to alias $_ to $?SELF.

I imagine

map { .foo } @objects;

to be interpreted as

map method { $?SELF.foo } @objects;

The distinguisher were the need of having a defined $?SELF in the
closure. My idea is the following:

| number of | as |
class | invocants | multi |
--------+-----------+--------------+
Sub | 0 | > 0 |
$?SELF | undef | := @?SELF[0] |
@?SELF | undef | invocants |
--------+-----------+--------------+
Method | 1 | > 1 |
$?SELF | invocant | := @?SELF[0] |
@?SELF | undef | invocants |
--------+-----------+--------------+

I used the @?SELF array mostly for illustrating my idea concerning
$?SELF, but it might be usefull for things like

multi sub foo
{
# use @?SELF here
}

as a catch-all for an unspecified number of parameters of type Any.
The type of a method's $?SELF is derived from the lexical class scope.
Subs in a class are just scoped there. A multi sub in a class is also
just scoped there and the class has no impact on the specificity of
any of the parameter types.
--
TSa (Thomas Sandlaß)

Reply all
Reply to author
Forward
0 new messages