Maps, nested maps and sink context
A map
does not return a List
, but rather a Seq
. A Seq
is a one-shot Iterable
sequence of values, and in sink context it will iterate its underlying iterator and discard the produced values. This is why a map
in sink context will iterate, but only one level deep. Add .flat
to sink even the inner values (by flattening them into a single top-level sequence):
<foo bar ber>.map({ $^a.comb.map: { $^b.say}}).flat # OUTPUT: «foobarber»
A List
would indeed not iterate its values in sink context, because a List
is a data structure that memorizes even lazily produced values so that they can be indexed repeatedly. Indeed, doing:
(<foo bar ber>.map: *.say).list;
Produces no output, because the Seq
was coerced into a List
, which does nothing in sink context.
Very few built-in operations on iterable data return a List
, since it would be a premature commitment to retain data. It's often useful to chain such operations together and have the data flow through them an item at a time, rather than having to be all held in memory at each intermediate step. This is what Seq
enables, and why so many things return it instead of List
.
I think this is because only the last statement of a map
is not sunk:
class A {
method sink() {
say "sunk"
}
}
<foo bar ber>.map: { A.new } # doesn't show 'sunk'
A.new; # shows 'sunk' once
<foo bar ber>.map: { A.new; 1 } # shows 'sunk' 3x
So the inner map
does not get sunk, and therefore doesn't run, because it's the sink-all
on the inner map (that gets called on the iterator by the sink
method) that makes things happen.