How can I use endless list without caching in Perl 6

The endless lazy lists are awesome!

> my @fibo = 0, 1, *+* ... *; > say @fibo[1000]; 43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875 

They automatically cache their values, which is very convenient ... most of the time. But when working with huge Fibonacci numbers ( example ), this can cause memory problems.

Unfortunately, I cannot figure out how to create a Fibonacci caching sequence. Is anyone

+6
source share
2 answers

One of the main problems is that you store it in an array, which, of course, stores all its values.

The next problem is a little more subtle, the syntax of LIST , CODE ... END the point sequence generator does not know how many of the previous values ​​the CODE part will request, so it stores all of them.
(He could look at arity / count CODE , but at the moment this is not like experimenting on REPL)

Then the problem arises of using &postcircumfix:<[ ]> on Seq calls .cache on the assumption that at some point you will ask for a different value.
(From looking at the source for Seq.AT-POS)

It is possible that future implementation may be better for each of these shortcomings.


You can create a sequence using another function to circumvent the current syntax limitations of a point sequence generator.

 sub fibonacci-seq (){ gather { take my $a = 0; take my $b = 1; loop { take my $c = $a + $b; $a = $b; $b = $c; } }.lazy } 

If you just repeat the values, you can just use them as is.

 my $v; for fibonacci-seq() { if $_ > 1000 { $v = $_; last; } } say $v; my $count = 100000; for fibonacci-seq() { if $count-- <= 0 { $v = $_; last; } } say chars $v; # 20899 

You can also use Iterator directly. Although this is not necessary in most cases.

 sub fibonacci ( UInt $n ) { # have to get a new iterator each time this is called my \iterator = fibonacci-seq().iterator; for ^$n { return Nil if iterator.pull-one =:= IterationEnd; } my \result = iterator.pull-one; result =:= IterationEnd ?? Nil !! result } 

If you have a fairly recent version of Rakudo, you can use skip-at-least-pull-one .

 sub fibonacci ( UInt $n ) { # have to get a new iterator each time this is called my \result = fibonacci-seq().iterator.skip-at-least-pull-one($n); result =:= IterationEnd ?? Nil !! result } 

You can also implement the Iterator class by wrapping it in Seq .
(this is basically how the methods that return the sequences are written to the Rakudo core)

 sub fibonacci-seq2 () { Seq.new: class :: does Iterator { has Int $!a = 0; has Int $!b = 1; method pull-one { my $current = $!a; my $c = $!a + $!b; $!a = $!b; $!b = $c; $current; } # indicate that this should never be eagerly iterated # which is recommended on infinite generators method is-lazy ( --> True ) {} }.new } 
+5
source

Apparently noob can't comment.

When defining a lazy iterator, such as sub fibonacci-seq2, you should mark the iterator as lazy by adding the "is-lazy" method, which returns True, for example:

 method is-lazy(--> True) { } 

This will allow the system to better detect possible endless points.

+5
source

Source: https://habr.com/ru/post/1014120/


All Articles