How can I stop Raku collapsing a list containing a single list?

Viewed 119

i've got a function, into which i want to be able to pass a list of lists, like in this artificial example:

sub print_lists(@input) {
    .say for @input
}

my @list_of_two_lists = ((1, 2), (3, 4)); 
print_lists(@list_of_two_lists);

this gives the following output, as expected:

(1, 2)
(3, 4)

but if i do this:

my @list_of_one_list = ((1, 2)); 
print_lists(@list_of_one_list);

i get this output:

1
2

i.e. it flattens the list containing one list of two elements, into a single list of two elements.

what am i doing wrong? what do i need to do if i want to be able to pass in a list containing a single list?

1 Answers

This behavior is a consequence of two Raku features, both of which are worth knowing.

The first is the Single Argument Rule. It's important enough to be worth reading the docs on, but the key takeaway is that when you pass a single list (as you do in with @list_of_one_list) constructs like for will iterate over each item in the list rather than over the list as a single item. In this case, that means iterating over the two items in the list, 1, and 2.

At this point, you might be thinking "but @list_of_one_list didn't have two items in it – it had one item: the list (1, 2)". But that's because we haven't gotten to the second point to understand: In Raku ( and ) are not what makes something a list. Instead, using the , operator is what constructs a list. This can take a tad bit of getting used to, but it's what allows Raku to treat parentheses as optional in many places that other languages require them.

To see this second point in action, I suggest you check out how .raku prints out your @list_of_lists. Compare:

my @list_of_one_list = ((1, 2));
say @list_of_one_list;  # OUTPUT: «[1, 2]»
my @list-of-one-list = (1, 2),;
say @list-of-one-list;  # OUTPUT: «[(1, 2)]»

And that's all the info you need to answer your question: simply add a , when you build your list of one list.

I hope that helped :)

Related