ajs / perl6-Math-Sequences

Useful mathematical sequences
Artistic License 2.0
3 stars 9 forks source link

Sequences should be implemented as functions (?) #39

Open AlexDaniel opened 5 years ago

AlexDaniel commented 5 years ago

Let's say we need 20000000001th element in sequence A000007:

use Math::Sequences::Integer; say @A000007[20000000000]

This code will run for quite a while and it'll consume a lot of memory.

However, looking at the implementation of the sequence:

our @A000007 is export = 𝕀.map: -> $n { 0 ** $n };

Not only the value can be returned right away, but also the elements do not need to be stored.

We can solve it by doing something like:

my @A000007 := class Foo does Iterable does Positional { multi method AT-POS(Int:D \pos) { 0 ** pos } }.new; say @A000007[0,1,2,200000000000000000000000]

This way no elements are stored and the result can be calculated for any element.

But! This only works for sequences that don't rely on previous elements. Let's say we have something that depends on previous values, like Fibonacci numbers (@A000292). Doing something like @A000045[200000] will make you store 200001 values which you might not need, and there's no obvious way to clear the memory. It is a big number, and it takes a few seconds to get it, but it's still somewhat reasonable. Moreover, many of the implemented sequences rely on existing sequences, so getting a value from one sequence can result in caching of multiple sequences.

Wouldn't it be better if sequences were implemented as functions, where the return value is a Seq? Users can then decide whether to cache these values or not, and the results can be disposed if needed to free the memory.

For example:

sub A000045 is export {
    0, 1, * + * ... *
}

You can then use it exactly the same way as you'd use @A000045 array, except that you don't need to type “@”.

lizmat commented 5 years ago

I guess the most efficient algorithm, especially for the cases where the sequence depends on N previous values, is to write a special Iterator class for it, and wrap that in a Seq.new().