Download the raw code.
use v6;
#make a BFS over all possible addition chains
sub chain(@c, $l, $n) {
for @c Z 1..* {for (@c) Z (($^a) xx $^b) -> $x, $y {
my $s = $x + $y;
if ($l) {
last if $s <= @c[*-1];
my $c = chain(@($s,@c), $l-1, $n) and return $c;
} else {
last if $s < $n;
$s == $n and return (@($s, @c));
}
}}
return Bool::False;
}
sub MAIN(Int $n) {
$n > 0 or say "Argument must be positive." and return;
$n == 1 and say "(1)" and return;
my $min = (log($n)/log(2)).ceiling - 1;
my $solution = ();
until ($solution = chain((1,), $min++, $n)) {};
say "(" ~$solution.reverse.join(", ") ~ ")";
}
The code produces correct results.
The return value of Bool::False
comes as a bit of a consistency surprise
after having returned List
s so far. return ()
(or just return
) would
return a list (retaining consistency), which would still evaluate to false
(retaining current semantics).
The for
loops were used without parentheses, but the if
and until
conditions got parentheses, for some reason.
The parentheses around @c
are not needed.
Given the throwing-around of list operators, one-letter variables, parameter
placeholders, stream-of-consciousness and
and or
statements, the code is
still refreshingly clear.
This solution does the usual recursive search through the solution space, same as many others.
There's no need to initialize $solution
to an empty Parcel
before the
until
loop, when that empty Parcel
is never used anyway — you could
declare the variable in the loop condition instead:
until (my $solution = chain((1,), $min++, $n)) {};
Could've saved one more line there. :-)
Short.