Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a finite list be lazy in Perl 6?

Suppose I have a sequence where I know the start and end points and the generator is straightforward. Can I make it lazy?

my @b = 0 ... 3;
say 'Is @b lazy? ' ~ @b.is-lazy; # Not lazy

I'd like to combination that known list with itself an unknown number of times but not generate the entire list immediately. I want @cross to be lazy:

my @cross = [X] @b xx $n;

I know I can do this through other simple matters or programming (and my Perl 5 Set::CrossProduct does just that), but I'm curious if there is some simple and intended way that I'm missing. Some way that doesn't involve me counting on my own.

As a side question, what's the feature of a sequence that makes it lazy? Is it just the endpoint? Is there a sequence with a known endpoint that can still be lazy if the generator can make infinite values between? I wondered how much information I have to remove and tried something like this:

my $m = @*ARGS[0];
my @b = 0, * + $m ... ^ * > 3;
say 'Is @b lazy? ' ~ @b.is-lazy;
say '@b: ' ~ @b;

Still, this is not lazy.

like image 337
brian d foy Avatar asked Apr 13 '17 08:04

brian d foy


3 Answers

The "is-lazy" method, in my opinion, is really a misnomer. The only thing it says, as cuonglm pointed out, is that just passes on that the underlying iterator claims to be lazy. But that still doesn't mean anything, really. An iterator can technically produce values on demand, but still claim it isn't lazy. And vice-versa.

The "is-lazy" check is used internally to prevent cases where the number of elements needs to be known in advance (like .roll or .pick): if the Seq / iterator claims to be lazy, it won't actually try, but fail or throw instead.

The only thing that .lazy does, is wrap the iterator of the Seq into another iterator that does claim to be lazy (if the given iterator claims it isn't lazy, of course). And make sure it won't pull any values unless really needed. So, adding .lazy doesn't tell anything about when values will be produced, only when they will be delivered. And it helps in testing iterator based logic to see how they would work with an iterator that claims to be lazy.

So, getting back to the question: if you want to be sure that something is lazy, you will have to write the iterator yourself. Having said that, the past months I've spent quite a lot of effort in making things as lazy as possible in the core. Notably xx N still isn't lazy, although it does produce a Seq nowadays. Making it lazy broke some spectests at some deep level I haven't been able to figure out just yet. Looking forward, I think you can be sure that things will be as lazy as makes sense generally, with maybe a possibility of indicating favouring memory over CPU. But you will never have complete control over builtins: if you want complete control, you will have to write it yourself.

like image 150
Elizabeth Mattijsen Avatar answered Nov 12 '22 16:11

Elizabeth Mattijsen


Yes, you can, using lazy method:

> my @b = (0 ... 3).lazy;
[...]
> say 'Is @b lazy? ' ~ @b.is-lazy;
Is @b lazy? True

There's nothing special Seq that make it be lazy, just its underlying Iterator does.

like image 5
cuonglm Avatar answered Nov 12 '22 18:11

cuonglm


As already pointed out, is-lazy does not really mean anything.

But I just wanted to mention that there is a page on rakudo wiki that gives a couple of clues on what you can expect from is-lazy.

like image 1
Aleks-Daniel Jakimenko-A. Avatar answered Nov 12 '22 17:11

Aleks-Daniel Jakimenko-A.