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: «f␤o␤o␤b␤a␤r␤b␤e␤r␤»

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.

Tags:

Raku