Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maps, nested maps and sink context

Tags:

raku

This code returns nothing

<foo bar ber>.map: { $^a.comb.map: { $^b.say}};

It contains two nested maps, both of them in sink context. it shouldn't work, because a list sunk in a sink context is a no-op.

However, this works:

<foo bar ber>.map: *.say; # OUTPUT: «foo␤bar␤ber␤»

and it's again a list in sink context. So why does it work?

like image 707
jjmerelo Avatar asked May 19 '18 08:05

jjmerelo


2 Answers

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.

like image 200
Jonathan Worthington Avatar answered Oct 13 '22 20:10

Jonathan Worthington


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.

like image 39
Elizabeth Mattijsen Avatar answered Oct 13 '22 19:10

Elizabeth Mattijsen