Home > Raku > Fooled by complexity

Fooled by complexity

And that fool would be me. After realising that HyperSeq is lazy, I managed to simplify the code in my last post.

sub needle(int \b) {
    sub is-pentagon($c is raw) { (1+sqrt(1+24*$c))%%6 }
    sub P($n is raw) { $n*(3*$n-1) div 2 }

    loop (my int $s = 1; $s < b; $s++) {
        my \bp = P(b);
        my \sp = P($s);
        if is-pentagon(bp + sp) && is-pentagon(bp - sp) {
            return |(b, $s);
        }
    }
}

sub infix:<notnilor>(\maybenil, \alternative) {
    maybenil =:= Nil ?? alternative !! maybenil
}

say (^∞).hyper(:batch(8), :degree(16)).map({.&needle notnilor Empty }).head;

The sub needle transforms its argument or returns Nil. By turning Nil into Empty, any call to .head will skip all values that where not a hit. At least for strongly CPU-bound tasks, which allow for small batch sizes, .hyper doesn’t overshoot much.

my atomicint $steps;
say (^∞).hyper(:batch(8), :degree(16)).map({$steps⚛++; .&needle notnilor Empty }).head;
say $steps;

# OUTPUT: (2167 1020)
          2246

Right now, almost all task are CPU-bound. Once Rakudo has learned to produce better bytecode being able to stop sibling threads will become desirable.

UPDATE

lizmat suggested to simplify the code further by replacing .&needle notnilor Empty with $_ with .&needle. This works because when with doesn’t fire, it returns Empty. That I did not know. It is specced and also applies to if. I filed the ENODOC under #4017. As it seems, we need to be careful not to run out of space on the interwebs by completing Raku’s docs.

Categories: Raku