Factorial and Memoizing

Just saw this post. Tried to comment there, but it failed.

As I understand it, Perl 6 is supposed to have a memoizer built-in, something like sub fact is cached ($n). But that definitely isn’t implemented in Rakudo yet.

There is an interesting way to do this that does work in Rakudo:

> my $fact = gather { take 1; my $a = 1; for 1..* { $a *= $_; take $a + 0 } }; say $fact[3];
6
> say $fact[3]
6
> say $fact[4]
24
> say $fact[10]
3628800
> say $fact.munch(20).perl
(1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000, 355687428096000, 6.402373705728e+15, 1.21645100408832e+17)

That defines $fact as a lazy list of the factorials, which you can then access as, say, $fact[10] (for 10!). The list will only contain actual values for the factorials you have asked for (and any others needed to compute those).

Edited to add: Just realized there is (almost?) an easier way of doing this.

> my $fact = [\*] 1..*; say $fact[3]
24
> $fact.munch(20).perl
(1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000, 355687428096000, 6.402373705728e+15, 1.21645100408832e+17, 2.43290200817664e+18)

As you can see, this is a much cleaner way of generating the list, but the indices are now off by one.

6 Responses to “Factorial and Memoizing”

  1. Eddward Says:

    I don’t have perl6 installed at work. Would the following work?

    my $fact = 1, [\*] 1..*;

    • colomon Says:

      I tried that first and it failed. 😦

    • Pm Says:

      Note that it would need to be parenthesized, because of item assignment:

      my $fact = (1, [\*] 1..*);

      It still doesn’t work (yet?), because itemizing the Parcel tends to make it eager, so we end up evaluating an infinite list. But the following does work:

      my $fact = (1, [\*] 1..100);

      which at least gets you to 100 factorial, and doesn’t take forever to do it. 🙂

      Pm

  2. RobertS Says:

    This works for me:

    my $fact = [\*] 1,1..*;
    say $fact.munch(20).perl;

    (1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000, 355687428096000, 6.402373705728e+15, 1.21645100408832e+17)

  3. Lanny Ripple Says:

    Also

    my $fact := (1, [\*] 1..*);
    say $fact[0..10].perl;

    (1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800)

Leave a reply to Lanny Ripple Cancel reply