# A Sequence represents anything that can lazily produce a sequence of values. # There are various concrete implementations of Sequence, the most common # being Seq, which represents a sequentially produced sequence. # # Sequences are born in a state where iterating them will consume the values. # However, calling .cache will return a List that will lazily reify to the # values in the Sequence. The List is memoized, so that subsequent calls to # .cache will always return the same List (safe as List is immutable). More # than one call to .iterator throws an exception (and calling .cache calls the # .iterator method the first time also). The memoization can be avoided by # asking very specifically for the Seq to be coerced to a List (using .List # or .list), a Slip (.Slip) or an Array (.Array). # # The actual memoization functionality is factored out into a role, # PositionalBindFailover, which is used by the binder to identify types that, # on failure to bind to an @-sigilled thing, can have .cache called on them # and get memoization semantics. This decouples this functionality from the # Sequence role, so other user-defined types can get access to this # functionality. my role PositionalBindFailover { has $!list; method cache() { nqp::isconcrete($!list) ?? $!list !! ($!list := List.from-iterator(self.iterator)) } multi method list(::?CLASS:D:) { nqp::isconcrete($!list) ?? $!list !! List.from-iterator(self.iterator) } method iterator() { die "Method 'iterator' must be implemented by " ~ self.^name ~ " because it is required by roles: PositionalBindFailover"; } } nqp::p6configposbindfailover(Positional, PositionalBindFailover); # Binder Routine.'!configure_positional_bind_failover'(Positional, PositionalBindFailover); # Multi-dispatch my role Sequence does PositionalBindFailover { multi method Array(::?CLASS:D:) { Array.from-iterator(self.iterator) } multi method List(::?CLASS:D:) { self.list.List } multi method Slip(::?CLASS:D:) { self.list.Slip } multi method Str(::?CLASS:D:) { self.cache.Str } multi method Stringy(::?CLASS:D:) { self.cache.Stringy } method Numeric(::?CLASS:D:) { self.cache.elems } multi method AT-POS(::?CLASS:D: uint $idx) is raw { self.cache.AT-POS($idx) } multi method AT-POS(::?CLASS:D: Int:D $idx) is raw { self.cache.AT-POS($idx) } multi method EXISTS-POS(::?CLASS:D: uint $idx) { self.cache.EXISTS-POS($idx) } multi method EXISTS-POS(::?CLASS:D: Int:D $idx) { self.cache.EXISTS-POS($idx) } multi method eager(::?CLASS:D:) { List.from-iterator(self.iterator).eager } multi method fmt(Sequence:D: |c) { self.cache.fmt(|c) } multi method gist(::?CLASS:D:) { self.cache.gist } } # vim: expandtab shiftwidth=4