Functional hypering
In my last post I used a one-shot-operator to improve neatness. Sadly, by defining custom operators we also improve Rakudo’s slowness. After staring at the code form quite some time, I realised that hyper- and meta-operators are code generators. They produce a new operator in-place, which is then used with two operands. In functional programming we do the same thing by returning a sub
from a sub
.
multi sub hyperize(&code, '«') {
sub (@little, @large) {
((@little xx *).flat Z @large).flat.map(&code)
}
}
my &hyper-assume = hyperize({&^a.assuming($^b)}, '«');
sub sc($_) {
.words».&{ hyper-assume((&lc, &uc), .comb)».().join }
}
Hyper-operators have a “direction” indicated by using »
or «
. Whereby the pointy bit points at the operand that doesn’t stop iteration. In hyperize
I’m doing the same with a string literal.
However, this is terribadly slow. The culprit is .assuming
, which has been reported to the authorities and will likely be fixed with RakuAST. In my case I don’t really need the fancy things .assuming
does.
sub simple-assume(&routine, |tail) {
sub (|c) {
my \real-args = \(|tail, |c);
routine(|real-args)
}
}
multi sub hyperize(&code, '«') {
sub (@little, @large) {
((@little xx *).flat Z @large).flat.map(&code)
}
}
my &hyper-assume = hyperize({simple-assume(&^a, $^b)}, '«');
sub sc($_) {
.words».&{ hyper-assume((&lc, &uc), .comb)».().join }
}
A speed up of factor 608 seems to be quite acceptable. No kidding, as soon as .assuming
is involved Rakudo refuses to inline and as a consequence of that to JIT.
I will try to provide a sub assuming
(right now we only have the method-form), provided I find a reasonable way to implement the advanced stuff, like skipping arguments with a Whatever
.
-
January 31, 2022 at 14:012022.05 foo = 42 – Rakudo Weekly News