I'm struggling to understand why the zip-add Z+ operator does not work on some cases.
I have some 2-element lists that I'd like to sum.
These work as expected whether I use lists or arrays:
say (1, 2) Z+ (3, 4) # (4, 6)
say [1, 2] Z+ (3, 4) # (4, 6)
say [1, 2] Z+ [3, 4] # (4, 6)
say (1, 2) Z+ [3, 4] # (4, 6)
Now we will do the same thing but I'll change the right operand with a value stored elsewhere. In this case I have an array of lists:
my @foo = (1,1), (2,2);
say @foo.WHAT; # (Array)
say @foo[1].WHAT; # (List)
say @foo[1]; # (2,2)
say (3,3) Z+ @foo[1]; # (5) ???
Which gives the unexpected (at least for me :)) result of (5).
There are a couple of ways to fix this.
First one is to force the got element to be a list:
my @foo = (1,1), (2,2);
say @foo.WHAT; # (Array)
say @foo[1].WHAT; # (List) <== It was already a list, but...
say @foo[1]; # (2,2)
say (3,3) Z+ @foo[1].list; # <== changed. (5,5)
And the other one is change the @foo definition to be a list instead of an array (either by is List or by binding := the value)
my @foo is List = (1,1), (2,2); # <=== Changed
say @foo.WHAT; # (Array)
say @foo[1].WHAT; # (List) <== It was already a list
say @foo[1]; # (2,2)
say (3,3) Z+ @foo[1]; # (5,5)
Why the first case didn't work?
Another way of looking at things...
==> No, it wasn't.
This is the primary key to your question in two respects:
First, as Liz notes, when trying to understand what's going on when you encounter a surprise, use
dd, notsay, becauseddfocuses on the underlying reality.Second, it's important to understand the role of
Scalars in Raku, and how that sharply distinguishesArrays fromLists.Another way to see the underlying reality, and the role of
Scalars, is to expand your examples a little:I'll draw attention to several aspects of the above:
A
Scalargenerally keeps quiet about itselfA
Scalarreturns the value it contains in an r-value context, unless you explicitly seek it out with.VAR.Scalarcontainers can be read/write or readonlyUntil I wrote this answer, I had not cleanly integrated this aspect into my understanding of Raku's use of
Scalars. Perhaps it's obvious to others but I feel it's worth mentioning here because theScalarindicated by the$(...)display fromddand.rakuis a readonly one -- you can't assign to it.An
Array"autovivifies" (automatically creates and binds) a read/writeScalarfor each of its elementsIf a value is assigned to an indexed position (say
@foo[42]) of a (non-native)Array, then if that element does not currently:exist(ie@foo[42]:existsisFalse), then a fresh read/writeScalaris "autovivified" as the first step in processing the assignment.A
Listnever autovivifies aScalarfor any of its elementsWhen a value is "assigned" (actually bound, even if the word "assigned" is used) to an indexed position in a
List, no autovivification ever occurs. AListcan includeScalars, including read/write ones, but the only way that can happen is if an existing read/writeScalaris "assigned" to an element (indexed position), egmy @foo := (42, $ = 99); @foo[1] = 100; say @foo; # (42 100).And now we can understand your code that yields
(5):† We're applying a coercive numeric operation (
+) to a list (Positionalvalue), not to its elements. A list, coerced to a number, is its "length" (count of elements). (Certainly for a non-sparse one. I'm not sure about sparse ones.)