Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Perl 6's Map give me a value in one case and a list in another?

Tags:

raku

I'm playing with Map and I get a result I don't understand.

First, I construct the Map. No big whoop:

> my $m = Map.new: '1' => :1st, '2' => :2nd;
Map.new(("1" => :st(1),"2" => :nd(2)))

I access a single element by the literal key and get back a Pair:

> $m<1>.^name
Pair
> $m<<1>>.^name
Pair

That's all fine.

If I try it with the key in a variable, I get back a List instead:

> my $n = 1
1
> $m<<$n>>.^name
List

That list has the right value, but why do I get a List in that case and not the $m<<1>> case?

And, once I have the list, I seem unable to chain another subscript to it:

> $m<<$n>>.[0]
===SORRY!=== Error while compiling:
Unable to parse quote-words subscript; couldn't find right double-angle quote
at line 2
like image 282
brian d foy Avatar asked May 22 '17 02:05

brian d foy


1 Answers

When you access an associative value like this, the compiler can tell that it need only ever return one value.

$m<  1  >
$m<< 1 >>

In Perl 6, a singular value will in many cases behave just like a list of one value.

42.elems == 1 # True
42.[0] =:= 42 # True

In the following case, the compiler can't immediately tell that it will only produce one value:

my $n = 1;
$m<< $n >>;

As it could produce 2 values:

my $o = '1 2';
$m<< $o >>;

If you want the string to be a single key, you have to use quotation marks.

$m<< "$o" >>

Or use the more appropriate {}

$m{ $n }

The $m<1> is just a combination of two features.

  1. Quotewords: ( qw<> and qqww<<>> )

    <   a  b  c   > eqv ("a", "b", "c")
    <  "a  b" c   > eqv (「"a」, 「b"」, "c") # three strings
    
    <<  a  b  c  >> eqv ("a", "b", "c")
    << "a  b" c  >> eqv ("a  b", "c")    # two strings
    
  2. Associative indexing:

    %h<   a  b  c  > eqv %h{ <   a  b  c  > }
    %h<< "a  b" c >> eqv %h{ << "a  b" c >> }
    

Also I now get back different values.

$m<   1  >.WHAT =:= Pair
$m<<  1 >>.WHAT =:= Pair
$m<< $n >>.WHAT =:= Pair # different

$m<< $o >>.WHAT =:= List

The reason $m<<$n>>.[0] doesn't work is the compiler thinks you are using a hyper postfix >>.[0].

There are a couple ways of working around that.

  1. Actually using a hyper postfix

    $m<<$n>>>>.[0]
    $m<<$n>>».[0]
    
  2. Use an unspace. (can never be inside of an operator so will split them up)

    $m<<$n>>\.[0]
    $m<<$n>>\     .[0]
    

I think this is a bug, as it doesn't make much sense to be matching a hyper postfix inside of a quotewords statement.
(It doesn't affect $m<<1>>.elems)

like image 173
Brad Gilbert Avatar answered Sep 30 '22 19:09

Brad Gilbert