# Perl Weekly Challenge 107

I wrote this week’s answers several days ago, but forgot to commit them. I ended up getting a new laptop and had to rewrite them. I think they ended up the same, but I guess no one knows for sure!

## Task 1: Self-descriptive Numbers

Write a script to display the first three self-descriptive numbers. As per wikipedia, the definition of “self-descriptive number” is:

In mathematics, a self-descriptive number is an integer m that in a given base b is b digits long in which each digit d at position n (the most significant digit being at position 0, and the least significant at position b−1) counts how many instances of digit n are in m.

For example:

```
1210 is a four-digit self-descriptive number:
Position 0 has value 1 i.e. there is only one 0 in the number
Position 1 has value 2 i.e. there are two 1 in the number
Position 2 has value 1 i.e. there is only one 2 in the number
Position 3 has value 0 i.e. there is no 3 in the number
```

Expected output:

```
1210, 2020, 21200
```

### Solution

See below for explanation and any implementation-specific comments.

```
sub challenge(Int $n) returns Str { # [1]
my @output;
for (^∞) -> $i { # [2][3]
my @digits = $i.comb;
my $valid = True;
for @digits.kv -> $index, $value {
$valid = @digits.grep($index).elems == $value;
last unless $valid; # [4]
}
@output.push($i) if $valid; # [5]
last if @output.elems == $n;
}
@output.join(', ');
}
sub MAIN(Int $n = 3) {
say challenge($n);
}
```

This program runs as such:

```
$ raku ch-1.raku
1210, 2020, 21200
```

### Explanation

We begin by defining a list to hold our output, then kick of an infinite loop starting at 0. For each number, we convert it to a list of digits (`.comb`

). For each index, value pair, we check if the input number has `$value`

number of `$index`

digits. So for 1210 we would check if it had 1 zero, 2 ones, 1 two, and 0 threes. If it meets the conditions, we add it to `@output`

. Finally, if we have found all 3 that we are looking for, we break out of the infinite loop and return.

#### Specific comments

- We make this generic by accepting the argument
`$n`

, but the fourth self-describing number is`3,211,000`

, and the fifth is`42,101,000`

, so this method would get slow very quickly. - We
*could*have said`loop`

to start an infinite loop, but then we wouldn’t have access to`$i`

. - When using this method, we always have to use the carrot (
`^`

) to say we are not including infinity. This is because it is impossible to be inclusive of infinity. `unless`

is just the opposite of`if`

. I feel this reads better than`last if !$valid`

.- I find the post-fix way of using conditionals to read better a lot of the time in Raku, as seen here.

## Task 2: List Methods

Write a script to list methods of a package/class.

### Example

Class definition:

```
package Calc;
use strict;
use warnings;
sub new { bless {}, shift; }
sub add { }
sub mul { }
sub div { }
1;
```

Expected output:

```
BEGIN
mul
div
new
add
```

### Solution

See below for explanation and any implementation-specific comments.

```
# Used for testing
class Calc { # [1]
method add {}
method mul {}
method div {}
}
sub challenge(Any $class) returns Str { # [2]
$class.^methods.map(*.gist).join("\n"); # [3][4]
}
sub MAIN {
say challenge(Calc.new);
}
```

This program runs as such:

```
$ raku ch-2.raku
add
mul
div
BUILDALL
```

### Explanation

The example shows a class definition in Perl, but we are using Raku, so we can just define our class using the `class`

keyword as shown. Additionally, we have a `BUILDALL`

method instead of `BEGIN`

.

Raku gives us the `^methods`

meta method to introspect an object’s methods, so we just have to utilize that on the input object!

#### Specific Comments

- In Perl, we have to define classes in their own file, but in Raku we can just use the
`class`

keyword. - All objects inherit from
`Any`

, so we are just saying we accept any class here. - Raku provides us a nice introspection method,
`^methods`

, which returns a list of defined methods and`BUILDALL`

. We can also pass in the flag`:local`

meaning “only show us methods defined in`Calc`

and not super classes,” or we could pass in`:all`

meaning “show us all methods that can act on this class.” - The returned type is
`List[Method]`

, so to cast everything to a string, we need to call each method’s`gist`

method.

## Final Thoughts

Once again, Raku makes these challenges super easy. Looking forward to something tougher in the future!