I’ve been doing the Perl Weekly
Challenges. The
latest
involved several sorts of introspection. (Note that this is open until
11 April 2021.)
TASK #1 › Self-descriptive Numbers
Write a script to display the first three self-descriptive numbers.
This is of course similar to task 2 of challenge 43, but not
identical, as we need multiple answers; I rewrote the code from
scratch. I eschewed most of the optimisations and just took the one
that the SDN must end in zero. The example makes it clear that what's
wanted is the first three SDNs in any base, and it's easiest just to
assume base 10 and ignore the "number must have length equal to the
base" constraint.
The algorithm is basically the same in each language: I have an array
ns
which is each digit in order, and an array d
which is the
number of times each digit occurs (so d[0]
is the number of
non-leading zeroes, etc.). If the number is self-describing these
arrays will match (with any d
in excess of the length of ns
being
zero). This code won't find SDNs above base 10, and it'll take a long
time there. (But I was polite and didn't just pull results from OEIS
A138480 or OEIS
A108551 which would get the answer with
much less work.)
In Raku:
sub sdn($count) {
my @r;
my $n=10;
while (@r.elems < $count) {
my @ns=map {$_+0}, sprintf('%d',$n).comb;
my @d=(0) xx 10;
map {@d[$_]++},@ns;
my $sd=1;
for 0..@ns.elems-1 -> $i {
if (@d[$i] != @ns[$i]) {
$sd=0;
last;
}
}
if ($sd && @ns.elems <= 9) {
for @ns.elems..9 -> $i {
if (@d[$i] != 0) {
$sd=0;
last;
}
}
}
if ($sd) {
push @r,$n;
}
$n+=10;
}
return @r;
}
The others are basically the same, except that in Rust I built the two
arrays in parallel
let mut ns: Vec<usize>=vec![];
let mut d: Vec<usize>=vec![0;10];
for i in n.to_string().chars() {
let k=i.to_digit(10).unwrap() as usize;
ns.push(k);
d[k] += 1;
}
because it felt clearer.
TASK #2 › List Methods
Write a script to list methods of a package/class.
Eugh. If I need to do this it is generally a sign that something has
gone Badly Wrong and I need to rethink my approach; it's a definite
bad code smell if I see it in someone else's program. (I did once
write a thing that used it, and it worked, but the code never got to
the point of usability for people other than me.) So while I know that
this is possible in Python and Ruby, though I believe not in Rust, I
only actually did it in Perl and Raku.
Perl (making sure that each thing in the module's namespace is a method):
use List::Util;
no strict 'refs';
foreach my $cm (sort keys %List::Util::) {
if (exists &{"List::Util::$cm"}) {
print "$cm\n";
}
}
Probably there's some way of getting at %modulename::
where
"modulename" is a string variable rather than a literal piece of text,
but I wasn't able to find it on a quick search and frankly wasn't
enthusiastic enough to look very hard. (Also one would ideally want
the contents of @modulename::ISA
in order to get all the methods of
the things one's inheriting from.)
Raku:
#! /usr/bin/perl6
use Pod::To::Text;
say Pod::To::Text.^methods.perl;
Full code on
github.
Comments on this post are now closed. If you have particular grounds for adding a late comment, comment on a more recent post quoting the URL of this one.