๐ Computing factorial! using Perl 6

# ๐ Computing factorial! using Raku

N. B. Perl 6 has been renamed to Raku. Click to read more.

Print the factorial of a given number.

By definition, the factorial of a positive integer number N is a product of all the integers numbering from 1 to N, including N. In Perl 6, this can be easily expressed with the use of a reduction operator:

`my \$n = 5;my \$f = [*] 1 .. \$n;say \$f;`

The record `[*] 1 .. \$n` is equivalent to the following expression:

`1 * 2 * 3 * 4 * ...* (\$n โ 1) * \$n`

A compact form `[*]` means that the operation character `*` is placed between the numbers in the given list.

The result in the case of `\$n` equals 5 is:

`120`

Another approach to calculating factorials is using recursion according to the formula: `n! = n (n - 1)!`.

On each iteration step, the function calls itself with decremented argument and should stop as soon as the value becomes less than two. In Perl 6, the knowledge of the fact that 1! is 1 can be encoded as a special case using multi-functions.

Multi-functions are subroutines prefixed with the multikeyword. They all share the name but may be distinguished by the type, number or values of their arguments.

For the factorial, define two multi-functions, one to calculate the factorial of the smallest numbers 0 and 1 (ignore the negative numbers for now):

`multi sub factorial(Int\$x where {\$x < 2}) {    return 1;}`

Another variant is for all the other numbers.

`multi sub factorial(Int \$x where {\$x >= 2}) {    return \$x * factorial(\$x - 1);}`

The whereclause in the function signature splits the calls to the factorialfunctions.

Calling the factorial with the number 5 calls the second variant a few times first, switching to the first variant when `\$x` reaches 1. As that variant does not iteratively call itself, the whole recursion loop stops.

`say factorial(5);`

Take a look at the signature of the function:

`(Int \$x where {\$x < 2})`

Here, the variable `\$x` is typed as `Int` (which is an integer in Perl 6) and restricted by the condition `{\$x < 2}` in the `where` clause. Therefore, this signature does its work to decide if the corresponding subroutine accepts the number or not.

Perl 6 offers another exciting thing, which gives quite impressive results in its application to the factorial task. It is possible to define your own postfix operators in Perl 6, so you can write `5!` in the code and get the factorial of five.

Here is an example of defining the postfix ! operator:

`sub postfix:<!>(\$n) {    return [*] 1 .. \$n;}`

Using it is straightforward:

`say 5!;`

This factorial operator is also applicable to variables, including the default variable:

`my \$x = 7;say \$x!; # Prints 5040say .! for 3..7;# 6, 24, 120, 720, 5040`

Recursive definition works with the user-defined operator, too. It is possible to use it even from the body of the operator definition itself:

`sub postfix:<!>(\$n) {    \$n <= 1 ?? 1 !! \$n * (\$n - 1)!}say 5!; # Prints 120`

The stop condition of the recursion is implemented here via the Boolean checkย `\$n <= 1`.ย In one-line functions like those shown above, it is not necessary to type theย returnkeyword, as the last calculated value is used as the result.

Update: Cached factorial computation