with Raku

This is my response to The Weekly Challenge #173.

You are given a positive integer,

Write a script to find out if the given number is

An esthetic number is a positive integer where every adjacent digit differs from its neighbour by 1.

For Example:

File: esthetic-number
`$n`

.
Write a script to find out if the given number is

`Esthetic Number`

.
An esthetic number is a positive integer where every adjacent digit differs from its neighbour by 1.

For Example:

5456 is an esthetic number as |5 - 4| = |4 - 5| = |5 - 6| = 1
120 is not an esthetic numner as |1 - 2| != |2 - 0| != 1

#! /usr/bin/env raku
unit sub MAIN (Int $n where $n > 0)); # [1]
say + is-esthetic($n); # [2]
sub is-esthetic ($number) # [2a]
{
my @digits = $n.comb; # [3]
my $current = @digits.shift; # [4]
while @digits.elems # [5]
{
return False
if all ($current != @digits[0] + 1), ($current != @digits[0] - 1); # [6]
$current = @digits.shift; # [7]
}
return True; # [8]
}

[1] Ensure a positive integer.

[2] Print «1» if the number is esthetic, and «0»
if not. I have delegated the computation to a procedure [2a] to make reuse easier. Note
the *Numeric Coercion Prefix Operator* `+`

used to get a numeric value
instead of the `True`

/`False`

returned by the procedure.

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

.

[3] Get the individual digits.

[4] Get the first digit.

[5] As long as there are more digits,

[6] The first `!=`

checks that the current digit is not one less
than the next one, and the second one that it is not one more than it. If both are true (set
up with an `all`

junction, we do not have an esthetic number (and returns
`False`

).

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

Junction.

[7] Move along, one more digit.

[8] We have reached the end, without failing. Then we have an esthetic number.

Running it:

$ ./esthetic-number 5456
1
$ ./esthetic-number 120
0

Looking good.

Note that one-digit numbers are considered esthetic by my implementation:

$ ./esthetic-number 1
1

Write a script to generate first `10 members`

of ```
Sylvester's
sequence
```

. For more informations, please refer to the
wikipedia page.

2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
16550664732451996419846819544443918001751315270637749784185138876653\
5868639572406808911988131737645185443

This sequence popped up in part 7 of my Centenary Sequences with Raku article, published in November 2020, as sequence #085:

(my $sum = 2, { my $c = $sum +1; $sum *= $c; $c } ... Inf) # 085

It was presented without explanation, but I'll do it this time:

(my $sum = 2, { my $c = $sum +1; $sum *= $c; $c } ... Inf)
# 1 ######## # 2 ############################### # 3 ####

[1] This (everything before the comma) is the first value in the sequence. We declare a
variable `$sum`

which is local to the sequence. The result of the assignment
is the value itself, which then is the first value.

[2] We set up a local variable `$c`

, and use that one to change the global
(from the point of view of this block) `$sum`

. The generated value for the
sequence is the last one in the block - which is the single `$c`

.

[3] This tells Raku to use the block to the left [2] to genereate values
*ad infinitum*.

I used it like this:

> say (my $sum = 2, { my $c = $sum +1; $sum *= $c; $c } ... Inf)[^8];
(2 3 7 43 1807 3263443 10650056950807 113423713055421844361000443)

Wrapping it up as a program is easy:

File: sylvesters-sequence#! /usr/bin/env raku
unit sub MAIN (Int $count where $count > 0 = 10);
my $ss := (my $sum = 2, { my $c = $sum +1; $sum *= $c; $c } ... Inf);
say $ss[^$count].join("\n"); # [1]

[1] The `join`

adds a newline between each value, and the `say`

adds one after the last one - giving the output as specified by the challenge.

Running it:

$ ./sylvesters-sequence
2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
16550664732451996419846819544443918001751315270637749784185138876653\
5868639572406808911988131737645185443

Looking good.

Curious about the eleventh value?

$ ./sylvesters-sequence 11
2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
16550664732451996419846819544443918001751315270637749784185138876653\
5868639572406808911988131737645185443
27392450308603031423410234291674686281194364367580914627947367941608\
692026226993634332118404582438634929548737283992369758487974306317\
730580753883429460344956410077034761330476016739454649828385541500\
213920807

The number of digits in each value increases at an alarming rate, after the first three values. Here is a Sylvester length sequence, giving us the number of digits instead of the actual values:

File: sylvesters-length-sequence```
#! /usr/bin/env raku
unit sub MAIN (Int $count where $count > 0 = 10);
my $ss := (my $sum = 2, { my $c = $sum +1; $sum *= $c; $c } ... Inf);
say $ss[^$count].map( *.chars ).join(", "); # [1]
```

[1] Note the `map`

we have inserted here, giving the number of characters (i.e.
digits), instead of the actual value. Doing this in the sequence would require a major
rewrite. (I have chosen to print a comma separated list this time, as the values are
much smaller.)

Running it:

$ ./sylvesters-length-sequence 12
1, 1, 1, 2, 4, 7, 14, 27, 53, 105, 209, 417

The pattern (from «4») seems to be «double the value and then subtract 1».

Generating some more values falsifies that assumption:

$ ./sylvesters-length-sequence 15
1, 1, 1, 2, 4, 7, 14, 27, 53, 105, 209, 417, 834, 1668, 3336

And that's it.