Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does lazyness of the slice index affects the slicing of an array/list? [RAKU]

When we slice an array with an index that exceeds the boundaries of the array we get as the result the undefined (Any)

When we pass the same slice index as a lazy list then we get as result the existing values of the array/list (and NOT any more than that):

my @a = ^5;

say @a[^10];        # (0 1 2 3 4 (Any) (Any) (Any) (Any) (Any))
say @a[lazy ^10];   # (0 1 2 3 4)

It is clear that lazyness of the slice index affects the result.

Trying to undestand the way things are and as a proof of concept I programmed my simple version of the slice mechanism:

my @a = ^5;

my @s1 = ^10;
my @s2 = lazy ^10;

sub postcircumfix:<-[ ]-> (@container, @index) {
    my $iter = @index.iterator;

    gather {
        loop {
            my $item := $iter.pull-one;

            if $item =:= IterationEnd {
                last;
            }

            with @container[$item] {
                take @container[$item]
            } else {
                @index.is-lazy ?? { last } !! take @container[$item];
            }
        }
    }
}

say @a-[@s1]-;   # (0 1 2 3 4 (Any) (Any) (Any) (Any) (Any))
say @a-[@s2]-;   # (0 1 2 3 4)

But I am wondering if my naive algorithm depicts the way that things are computed under the hood !

like image 397
jakar Avatar asked Sep 29 '20 14:09

jakar


People also ask

What is the difference between list slicing and slicing arrays?

However, slicing arrays are different from slicing lists so that the users can slice in multiple dimensions in arrays. Moreover, the list slicing returns a new array, but the slice in the array returns the view of the same array.

What does it mean to slice a Python array?

Slicing a python array means getting items from a particular index to another particular index—for instance, printing elements from index two to seven from an array containing ten elements. The users can similarly slice the python lists.

How to find a slice of an array in JavaScript?

There are the following three ways to find a slice of an array: Let's discuss each method in detail. It is a native method for getting a slice of an array. In this method, first, we find the start and end index of the given array. After that, we create an empty array (sliced array) of size (endIndex - startIndex).

What are the default start and step for array slicing?

As we can see for both the cases, start and step are set by default to 0 and 1. The sliced arrays contain elements of indices 0 to (stop-1). This is one of the quickest methods of array slicing in Python.


1 Answers

The source for how things are done under the hood can be found in array_slice.pm6.

Specifically, you can see the following at L73:

    if is-pos-lazy {
        # With lazy indices, we truncate at the first one that fails to exists.
        my \rest-seq = Seq.new(pos-iter).flatmap: -> Int() $i {
            nqp::unless(
              $eagerize($i),
              last,
              $i
            )
        };
        my \todo := nqp::create(List::Reifier);
        nqp::bindattr(todo, List::Reifier, '$!reified', eager-indices);
        nqp::bindattr(todo, List::Reifier, '$!current-iter', rest-seq.iterator);
        nqp::bindattr(todo, List::Reifier, '$!reification-target', eager-indices);
        nqp::bindattr(pos-list, List, '$!todo', todo);
    }
    else {
        pos-iter.push-all: target;
    }

So, as you've surmised, it does indeed stop after a list item doesn't exist. This is no doubt becaue many lazy lists are infinite, and iterators don't provide a way to know if they are infinite or not (the generator may be non-determinative).

If you really want to enable such a thing, you could, for instance, write your own slicer that handles lazy lists where an element may not be available, but you have to take care to ensure that things are only eagerly evaluated if you know they're finite:

multi sub postcircumfix:<-[ ]-> (@a, @b) {
  lazy gather {
    take @a[$_] for @b;
  }
}

my @a = ^5;
my @b = lazy gather { 
  for ^10 -> $i { 
    # So we can track when elements are evaluated
    say "Generated \@b[$i]"; 
    take $i;
  } 
};

say "Are we lazy? ", @a-[@b]-;
say "Let's get eager: ", @a-[@b]-.eager;
say "Going beyond indices: ", @a-[@b]-[11]

The output of this is

Are we lazy? (...)
Generated @b[0]
Generated @b[1]
Generated @b[2]
Generated @b[3]
Generated @b[4]
Generated @b[5]
Generated @b[6]
Generated @b[7]
Generated @b[8]
Generated @b[9]
Let's get eager: (0 1 2 3 4 (Any) (Any) (Any) (Any) (Any))
Going beyond indices: Nil
like image 56
user0721090601 Avatar answered Oct 21 '22 10:10

user0721090601