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