class Seq

An iterable, potentially lazy sequence of values
class Seq is Cool does Iterable does Sequence { }

A Seq represents anything that can produce a sequence of values. A Seq is born in a state where iterating it will consume the values. Calling .cache on a Seq will make it store the generated values for later access.

A high-level construct to generate a Seq is gather/take, as well as many built-in methods like map and grep, low-level constructors to create a Seq from an iterator or from looping constructs are available too.

A Seq can also be constructed with the sequence operator ... or one of its variants.

my $s = (1...5);
    say $s;              # OUTPUT: Ā«(1 2 3 4 5)ā¤Ā»
    say $s.^name;        # OUTPUT: Ā«Seqā¤Ā»

Assigning the values of a Seq to an array consumes a Seq that is not lazy. Use the lazy statement prefix to avoid a Seq from being iterated during the assignment:

# The Seq created by gather ... take is consumed on the spot here.
my @a = gather do { say 'consuming...'; take 'one' };  # OUTPUT: Ā«consuming...ā¤Ā»

# The Seq here is only consumed as we iterate over @a later.
my @a = lazy gather do { say 'consuming...'; take 'one' };  # outputs nothing.
.say for @a;  # OUTPUT: Ā«consuming...ā¤oneā¤Ā»

A typical use case is method lines in IO::Handle, which could use a lot of memory if it stored all the lines read from the file. So

for open('README.md').lines -> $line {
    say $line;
}

won't keep all lines from the file in memory.

This implies that you cannot iterate the same Seq object twice (otherwise it couldn't throw away old values), so this dies:

my @a = 1, 2, 3;
    my @b = <a b c>;
    my \c = @a Z=> @b;
    .say for c;
    .say for c; # fails
    CATCH { default { put .^name, ': ', .Str } };
    # OUTPUT: Ā«X::Seq::Consumed: This Seq has already been iterated, and its values consumed
    # (you might solve this by adding .cache on usages of the Seq, or
    # by assigning the Seq into an array)Ā»

Caution: No program should ever assume a Seq may only be iterated once even if not cached by the program. Caching is a volatile state exposed to the developer as an optimization. The Seq may become cached by many operations, including calling .raku (.perl before version 2019.11) on the Seq (if called prior to a non-cached iteration). From version 6.d, .raku (again, .perl before version 2019.11) can be called on consumed Seq. If a program assumes a Seq can only iterate once, but then is later changed to call one of these operations during the loop, that assumption will fail.

On a cached Seq, the cached list is used when &infix:<eqv>, .Slip, .join, .List, .list, .eager, .Array and .is-lazy are called.

You can smartmatch a regex with Seq, even if it's infinite

my @fib = 1,1, *+* ... *;
    say @fib[^1000] ~~ /^9999/; # OUTPUT: Ā«Nilā¤Ā»

However, infinite or lazy Seq will be vivified when doing the match, leading to possibly infinite loops, so be sure to limit search somehow.

Methods

method new

proto method new(Seq: |) {*}
multi method new(Seq: Iterator:D $iter)
multi method new(Seq:)

Creates a new Seq object from the supplied iterator passed as the single argument. Creates an empty Seq if called with no argument.

method iterator

method iterator(Seq:D:)

If the Seq is not cached, returns the underlying iterator and marks the invocant as consumed. If called on an already consumed sequence, throws an error of type X::Seq::Consumed.

Otherwise returns an iterator over the cached list.

method is-lazy

method is-lazy(Seq:D:)

Returns True if and only if the underlying iterator or cached list considers itself lazy. If called on an already consumed sequence, throws an error of type X::Seq::Consumed.

method Seq

multi method Seq(Seq:D:)

Clones the object.

method Capture

method Capture()

Coerces the object to a List, which is in turn coerced into a Capture.

method elems

method elems(Seq:D:)

Returns the number of values in the sequence. If this number cannot be predicted, the Seq is cached and evaluated till the end.

Because an infinite sequence cannot be evaluated till the end, such a sequence should be declared lazy. Calling .elems on a lazy Seq fails with X::Cannot::Lazy.

method from-loop

multi method from-loop(&body, :$label)
    multi method from-loop(&body, &cond, :$repeat!, :$label)
    multi method from-loop(&body, &cond, :$label)
    multi method from-loop(&body, &cond, &afterwards, :$label)

These methods create new Seq-based callbacks.

In general, it produces an infinite Seq by calling &body each time a new element is requested, using the return value from &body as the item. This emulates (or implements) a loop { body } construct.

When the multi includes &cond, it's invoked before each call to &body, and terminates the sequence if &cond returns a false value. If $repeat is set to a true value, the first call to &cond is omitted, and &body called right away. This emulates (or implements) while cond { body } and repeat { body } while cond loops.

If present, &afterward will be called after each call to &body.

method sink

method sink(--> Nil)

Calls sink-all if it is an Iterator, sink if the Sequence is a list.

say (1 ... 1000).sink; # OUTPUT: Ā«Nilā¤Ā»

This is something you might want to do for the side effects of producing those values.

method skip

multi method skip(Seq:D:)
    multi method skip(Seq:D: Whatever)
    multi method skip(Seq:D: Callable:D $w)
    multi method skip(Seq:D: Int() $n)
    multi method skip(Seq:D: $skip, $produce)

Returns a Seq containing whatever is left of the invocant after throwing away $n of the next available values. Negative values of $n count as 0. Also can take a WhateverCode to indicate how many values to skip from the end. Will block on lazy Seqs until the requested number of values have been discarded.

say (1..5).Seq.skip;      # OUTPUT: Ā«(2 3 4 5)ā¤Ā»
    say (1..5).Seq.skip(3);   # OUTPUT: Ā«(4 5)ā¤Ā»
    say (1..5).Seq.skip(5);   # OUTPUT: Ā«()ā¤Ā»
    say (1..5).Seq.skip(-1);  # OUTPUT: Ā«(1 2 3 4 5)ā¤Ā»

Calling it with Whatever will return an empty Seq:

say <1 2 3>.Seq.skip(*);  # OUTPUT: Ā«()ā¤Ā»

The multi that uses a Callable is intended mainly to be used this way:

say (1..5).Seq.skip(*-3); # OUTPUT: Ā«(3 4 5)ā¤Ā»

Instead of throwing away the first $n elements, it throws away everything but the elements indicated by the WhateverCode, in this case all but the last three elements.

As of language version 6.e (early implementation exists in Rakudo compiler 2022.12+), it is also possible to specify multiple argument values. These are then interpreted as number of values to produce, then skip, then produce, etc.

say (1..12).Seq.skip(2,3,4); # OUTPUT: Ā«(3 4 5 10 11 12)ā¤Ā»

This first skipped 2 values, then produced 3 values (3, 4, 5), skipped 4 values and then produced the rest (10, 11, 12).

If the final value specified is in a "produce" position, then the rest of the Seq will be skipped. If the final value is in a "skip" position, then the rest of the Seq will be produced.

say (1..10).Seq.skip(2,3,1,2); # OUTPUT: Ā«(3 4 5 7 8)ā¤Ā»
    say (1..10).Seq.skip(2,3,1);   # OUTPUT: Ā«(3 4 5 7 8 9 10)ā¤Ā»

If a Whatever is specified in a "produce" position, it will cause the rest of the Seq to be produced. Otherwise, it will cause the rest if the Seq to be skipped.

say (1..10).Seq.skip(2,*);   # OUTPUT: Ā«(3 4 5 6 7 8 9 10)ā¤Ā»
    say (1..10).Seq.skip(2,3,*); # OUTPUT: Ā«(3 4 5)ā¤Ā»

If you want to start with producing values instead of skipping, specify 0 as the first value.

say (1..10).Seq.skip(0,3,4); # OUTPUT: Ā«(1 2 3 8 9 10)ā¤Ā»

If you want an unending repeating pattern of skips and produces, you can specify the arguments as an unending Seq themselves.

say (^20).Seq.skip(|(2,3) xx *); # OUTPUT: Ā«(0 1 5 6 10 11 15 16)ā¤Ā»

multi method slice

method slice(Seq:D: *@indices --> Seq:D)

Available as of the 2021.02 release of the Rakudo compiler.

The slice method takes a number of monotonically increasing indices for which to produce the value from the invocant in a new Seq. Indices can be single numbers or ranges, as long they are increasing in value.

This provides a more efficient way of getting specific values out of a Seq than either caching the Seq or converting it to a List or Array.

say (1..10).Seq.slice(0, 3..6, 8);  # OUTPUT: Ā«(1 4 5 6 7 9)ā¤Ā»

See Also

class Array

Sequence of itemized values

class Bag

Immutable collection of distinct objects with integer weights

class BagHash

Mutable collection of distinct objects with integer weights

class Capture

Argument list suitable for passing to a Signature

class Hash

Mapping from strings to itemized values

class IterationBuffer

Low level storage of positional values

class List

Sequence of values

class Map

Immutable mapping from strings to values

class Mix

Immutable collection of distinct objects with Real weights

class MixHash

Mutable collection of distinct objects with Real weights

class NFC

Codepoint string in Normal Form C (composed)

class NFD

Codepoint string in Normal Form D (decomposed)

class NFKC

Codepoint string in Normal Form KC (compatibility composed)

class NFKD

Codepoint string in Normal Form KD (compatibility decomposed)

class Pair

Key/value pair

class PseudoStash

Stash type for pseudo-packages

class Range

Interval of ordered values

class Set

Immutable collection of distinct objects

class SetHash

Mutable collection of distinct objects

class Slip

A kind of List that automatically flattens into an outer container

class Stash

Table for "our"-scoped symbols

class Uni

A string of Unicode codepoints

class utf8

Mutable uint8 buffer for utf8 binary data

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.