by Arne Sommer

# Just the Fact with Raku

 Published 26. February 2022. Updated 12. march 2022

This is my response to the Perl Weekly Challenge #153.

## Challenge #153.1: Left Factorials

Write a script to compute `Left Factorials` of `1 to 10`. Please refer OEIS A003422 for more information.

Expected Output: ```1, 2, 4, 10, 34, 154, 874, 5914, 46234, 409114 ```

What exactly is the meaning of compute? Let us start with a very silly version:

File: left-factorials-silly ```#! /usr/bin/env raku say "1, 2, 4, 10, 34, 154, 874, 5914, 46234, 409114"; ```

Running it gives what you would expect:

```\$ ./left-factorials-silly 1, 2, 4, 10, 34, 154, 874, 5914, 46234, 409114 ```

The OEIS article reveals that the formula for the `n`th value is `(0! .. n!).sum`. The first value in the sequence is zero, but the challenge skips that one and starts with 1 (which according to OEIS is the second value). Let us do what the challenge asks for, inititally at least.

File: left-factorials-loop ```#! /usr/bin/env raku my \$lf := gather { my \$index = 0; #  loop #  { take (0 .. \$index++).map({ [*] (1 .. \$_) }).sum; #  } } say \$lf[^10]].join(", "); ```

 Used to keep track of the current index, as the formulae requires it.

 An eternal loop, giving one value for each iteration.

{3] The inside of the «map» (`({ [*] (1 .. \$_) })` is the faculty function, implemented with the Reduction Metaoperator `[]` that (in this case, as the operator is `*`) multiplies all the values together. The values are the numbers from 1 up to `\$_`. The first part (`(0 .. \$index++).map(...)`) gives us all the indices, and maps them to the corresponding faculty value. (I.e. 3 gives 3!). The final `.sum` adds them together, giving the current value in the sequence.

See docs.raku.org/language/operators#Reduction_metaoperators for more information about the Reduction Metaoperator `[]`.

Running it:

```\$ ./left-factorials-loop 1, 2, 4, 10, 34, 154, 874, 5914, 46234, 409114 ```

Note that this will recalculate all the factorial values a lot of times. We can - and indeed should - cache them:

File: left-factorials-loop-cached ```#! /usr/bin/env raku my \$lf := gather { my \$index = 0; my \$prev = 0; #  loop { take \$prev += ( [*] (1 .. \$index++) ).sum; #  } } say \$lf[^10].join(", "); ```

 The previous value in the sequence, used by the next one. This is the cached value.

 Get the faculty of the new index, and add that to the previous value.

The result is as expected:

```\$ ./left-factorials-loop-cached 1, 2, 4, 10, 34, 154, 874, 5914, 46234, 409114 ```

Let us amend this, so that we can get the first (or zero) value of 0, as OEIS would like us to:

File: left-factorials-loop-cached-one ```#! /usr/bin/env raku unit sub MAIN (:z(:\$zero-based)); my \$lf := gather { my \$index = 0; my \$prev = 0; take 0 if \$zero-based; #  loop { take \$prev += ( [*] (1 .. \$index++) ).sum; } } say \$lf[^10].join(", "); ```

 Instead of rewriting the loop, we can just insert the initial zero like this.

Running it gives the expected result:

```\$ ./left-factorials-loop-cached-one 1, 2, 4, 10, 34, 154, 874, 5914, 46234, 409114 \$ ./left-factorials-loop-cached-one -z 0, 1, 2, 4, 10, 34, 154, 874, 5914, 46234 ```

We can actually do this with a proper Raku sequence, which is very compact:

File: left-factorials-seq-zero ```#! /usr/bin/env raku unit sub MAIN (:c(:\$count) = 10); my \$lf := ( 0, 1, ( * + ([*] 1 .. ++\$) ) ... Inf ); # ########    #################  ##### say \$lf[^\$count].join(", "); ```

 The first value is 0.

 The second value is 1.

 Then a rule for all the values following the first two. Start with the previous value in the sequence (the first `*`), and add it to the expression after the plus sign. That expression is the faculty function applied to `\$`, which is an anonymous state variable (that pops into existence when we use it, and keeps the value between calls).

See docs.raku.org/syntax/\$ for more information about the anonymous state variable `\$`.

 Go on indefinitely.

The result is as expected:

```\$ ./left-factorials-seq-zero 0, 1, 2, 4, 10, 34, 154, 874, 5914, 46234 ```

The non-zero version is a little bit trickier:

File: left-factorials-seq ```#! /usr/bin/env raku unit sub MAIN (:c(:\$count) = 10); my \$lf := ( \$ = 1, ( * + ([*] 1 .. ++\$) ) ... Inf ); #  say \$lf[^\$count].join(", "); ```

 This time we skip the initial zero in the sequence, but we have to initialise the state variable to 1 (which is also the first value, as it is returned from the assignment), so that it starts with the correct index value.

All is well:

```\$ ./left-factorials-seq-zero 0, 1, 2, 4, 10, 34, 154, 874, 5914, 46234 \$ ./left-factorials-seq-zero -c=12 0, 1, 2, 4, 10, 34, 154, 874, 5914, 46234, 409114, 4037914 ```

## Challenge #153.2: Factorions

You are given an integer, `\$n`.

Write a script to figure out if the given integer is factorion.

A factorion is a natural number that equals the sum of the factorials of its digits.

Example 1: ```Input: \$n = 145 Output: 1 Since 1! + 4! + 5! => 1 + 24 + 120 = 145 ``` Example 2: ```Input: \$n = 123 Output: 0 Since 1! + 2! + 3! => 1 + 2 + 6 <> 123 ```

Let us go for a compact version:

File: factorions ```#! /usr/bin/env raku unit sub MAIN (Int \$n where \$n > 0); #  say + (\$n.comb.map({ [*] (1 .. \$_) }).sum == \$n); #  ```

 Ensure a natural number, i.e. a positive integer.

 We use `comb` to get a list of digits, then `map` to apply the faculty function (as shown in the first part of the challenge) on them. Then we add them together (with `sum`) and compare the result with the initial number. The result of this comparison is a Boolean value, so we coerce it to an integer (True => 1, False => 0) with the Numeric Coercion Prefix Operator `+` (that has a very impressive (as in long) name, especially compared with the single character of the operator itself).

See docs.raku.org/routine/+ for more information about the Numeric Coercion Prefix Operator `+`.

Running it:

```\$ ./factorions 145 1 \$ ./factorions 123 0 ```

Ok.

Let us have a go at the Factorion Sequence:

File: factorion-seq ```#! /usr/bin/env raku unit sub MAIN (:c(:\$count) = 10); my \$fs := ( my \$i = 1, { (++\$i).comb.map({ [*] (1 .. \$_) }).sum == \$i ?? \$i !! next }  ... Inf ); say \$fs[^\$count].join(", "); ```

 Note the `next` inside the rule (as `map` is a loop in disguise), instead of the more intuitive `grep` on the outside. This is necessary, as `grep` will coerce whatever it is used on to a list. Expanding an eternal sequence is not a good idea.

### Correction 12. March 2022

The statement above is wrong, as lists can be lazy. We can use `grep` here. See Fooled by a Sequence, Twice for details.

Also note the ternary operator `??` and `!!` instead of a full blown `if` and `else`.

See docs.raku.org/routine/grep for more information about `grep`.

See docs.raku.org/language/operators#index-entry-operator_ternary for more information about the ternary operator `??` / `!!`.

Running it:

```\$ ./factorion-seq ^C ```

It hangs.

Looking it up (at mathworld.wolfram.com/Factorion.html) tells us that there are only 4 values, so the program happily goes on to infinity searching for the default 10 values. (Well, it tries to. Infinity is not reachable.)

This is the four values:

```\$ ./factorion-seq -c=4 1, 2, 145, 40585 ```

And that's it.