Perl 6 provides a wide array of list-related features, including eager, lazy, and parallel evaluation of sequences of values, and arrays offering compact and multi-dimensional storage. Laziness in particular needs careful handling, so as to provide the power advanced users desire while not creating surprises for typical language users who have the (reasonable) expectation that an assignment into an array will have immediate effect. Additionally, it is important to give the programmer control of when values will and won't be retained. Finally, all of this needs to be done in a way that provides the convenience that a Perl is expected to provide, while still having a model that can be understood through understanding a small number of rules.

In Perl 6, we use the term "sequence" to refer to something that can, when requested, produce a sequence of values. Of note, it can only be asked to produce them once. We use the term "list" to refer to things that hold (and so remember) values. There are various concrete types that represent various kinds of list and sequence with different semantics:

(1, 2, 3) # a List, the simplest kind of list
[1, 2, 3] # an Array, a list of (assignable) Scalar containers
|(1, 2) # a Slip, a list which flattens into a surrounding List
$*IN.lines # a Seq, a sequence that can be processed serially
(^1000).race # a HyperSeq, a sequence that can be processed in parallel

The @ sigil in Perl indicates "these", while $ indicates "the". This kind of plural/single distinction shows up in various places in the language, and much convenience in Perl comes from it. Flattening is the idea that an @-like thing will, in certain contexts, have its values automatically incorporated into the surrounding list. Traditionally this has been a source of both great power and great confusion in Perl. Perl 6 has been through a number of models relating to flattening during its evolution, before settling on a straightforward one known as the "single argument rule".

The single argument rule is best understood by considering the number of iterations that a for loop will do. The thing to iterate over is always treated as a single argument to the for loop, thus the name of the rule.

The first two are equivalent because parentheses do not actually construct a list, but only group. It is the infix:<,> operator that forms a list. The third also performs three iterations, since in Perl 6 [...] constructs an Array but does not wrap it into a Scalar container. The fourth will do two iterations, since the argument is a list of two things; that they both happen to have the @-sigil does not, alone, lead to any kind of flattening. The same goes for the fifth; infix:<,> will happily form a list of one thing.

Re-using any of these arrays will work out fine. Of course, the memory behavior of this program is radically different, and it will be slower due to all of the extra Scalar containers created (resulting in extra garbage collection) and poor locality of reference (we have to talk about the same string many times over the programs lifetime).

Occasionally it can be useful to request that a Seq cache itself. This can be done by calling the cache method on a Seq, which makes a lazy List from the Seq and returns it. Subsequent calls to cache will return the same lazy list. Note that the first call to cache counts as consuming the Seq, and so it will not work out if any prior iteration has taken place, and any later attempt to iterate the Seq after calling cache will also fail. It is only .cache which may be called more than once.

A Seq does not do the Positional role like a List. Therefore, it can not be bound to an @-sigil variable:

my @lines := $*IN.lines; # Dies

One consequence of this is that, naively, you could not pass a Seq as an argument to be bound to an @-sigil parameter:

sub process(@data) {
}
process($*IN.lines);

This would be rather too inconvenient. Therefore, the signature binder (which actually uses ::= assignment semantics rather than :=) will spot failure to bind the <@>-sigil parameter, and then check if the argument does the PositionalBindFailover role. If it does, then it will call the cache method on the argument and bind the result of that instead.

Both Seq and List, along with various other types in Perl 6, do the Iterable role. The primary purpose of this role is to promise that an iterator method is available. The average Perl 6 user will rarely need to care about the iterator method and what it returns.

The secondary purpose of Iterable is to mark out things that will flatten on demand, when the flat method or function is used on them.

Another use of flat is to flatten nested List structure. For example, the Z (zip) operator produces a List of List:

say (1, 2 Z 'a', 'b').perl; # ((1, "a"), (2, "b")).Seq

A flat can be used to flatten these, which is useful in conjunction with a for loop using a pointy block with multiple parameters:

for flat 1, 2 Z 'a', 'b' -> $num, $letter { }

Note that flat respects Scalar containers, and so:

for flat $(1, 2) { }

Will only do one iteration. Remember that an Array stores everything in a Scalar container, and so flat on an Array - short of weird tricks with binding - will always be the same as iterating over the Array itself. In fact, the flat method on an Array returns identity.