Archive for February, 2022

Looplessly simple

February 22, 2022 1 comment

PWC#153 is asking us to do two things that are almost comically simple, given we omit loops.

Task one would like us to output the first 10 left factorials.

sub MAIN() {
    my \leftfact = [\+] 0, 1, * * ++$ … ∞;
    say leftfact[1..10];

I’m doing so by writing down the definition of left factorials as a sequence and then indexing into the resulting lazy list.

In the 2nd task we need to check if the sum of the factorials of a digit equal that number.

sub MAIN(Int() $n) {
    my \fact = 1, * * ++$ … ∞;
    say fact[$n.comb].sum == $n ?? 1 !! 0

Again, I write down the definition of a factorial to get a lazy list in return. Then I can index into that list with a list of chars. Thankfully, Raku is considered enough to turn that list of chars into Ints for me. The sum is then checked against the whole number.

If you wonder what numbers are factorions, we can calculate them all.

my \fact = 1, * * ++$ … ∞;
.say for (^∞).hyper(:batch(1000)).grep({ fact[.comb].sum == .Int });

Hypering and sequences don’t really mix. State variables even less so. Luckily we only ever need the factorials of 0 to 10. I prime the lazy list with those values and happily hyper away.

I had a peak into the solutions on Rosattacode for left factorials. While scrolling past so many loops I had to think of Mr T.

Categories: Raku

Fuzzy commands

February 9, 2022 1 comment

Reading can make one learned. Today I had a peak into lizmat´s new module shorten-sub-commands and learned about Parameter.constraint_list. We need this method to introspect a routines literal parameters.

augment class Parameter {
    method literal {
        ! && !self.named && self.type ~~ Str|Numeric && self.constraint_list == 1
            ?? self.constraint_list.head
            !! Nil

multi sub foo('literal', 42) { }
multi sub foo($not-a-literal, 42) { }
.say for &foo.candidates».signature».params».literal;

# OUTOUT: (literal 42)
#         (Nil 42)

We can generalise lizmat´s idea of transforming command line arguments.

multi sub MAIN('foo', |c) { say 'foo', @*ARGS[0] }
multi sub MAIN('Barbara', |c) { say ['bar', @*ARGS[0]] }

sub transform-first-arg(Mu:D $test is raw, &mapper) {
    &MAIN.add_dispatchee: sub (Str:D $subcommand, |c) is hidden-from-USAGE {
        my &this-candidate := &?ROUTINE;
        my @real-subcommands = &MAIN.candidates.grep(* !=:= &this-candidate)».signature».params».[0]».literal;
        if $subcommand ~~ $test {
            MAIN(mapper($subcommand), |c)

transform-first-arg({ .lc.contains(<fo ba>.any) }, { .trans: ['fo', /:i ba.*/] => ['foo', 'Barbara'] });

This program is now very generous when it comes to it’s first argument. Even !./% bAR will result in the right MAIN-candidate to be called.

I used augment because this doesn’t feel like an ENODOC. One needs to know quite a lot of the internal workings of Parameter to make use of method constraint_list. We may have to support more then just string and numeral literals in the future. So maybe there is a PR in order.

Categories: Raku