Occasionally I play with Project Euler's problems. Although they should be focused on smart algorithms, many of them can be easily solved with naive ones, often brute force, and unless there's a good reason not to do so, it's a pleasure for me to handle them with just a bunch of lines of Perl code.

Now, in a particular one I needed to adjoin the numbers 1,2,3,... (as strings) up to a length of at least 10^6. The code I used is:

my ($s,$x)=''; $s .= ++$x while length($s) < 1_000_000;

Here I'm bothered by the lexical $x: with a little more effort I may have hidden it suitably, but of course I was mostly concerned with completing the task quickly enough...

Coming to Perl 6, we have lazy lists evaluation there, and the reduce metaoperator (yes, I am aware of List::Util's reduce) and if I know in advance that the loop above stops at $x==185185 I can do, in a single statement:

my $s = [~] 1..185185;

And that is IMHO very elegant, and practical too. Yet, it would be nice if there were a way to have both the simplicity and elegance of that line of code and do the same as the Perl 5 code above without necessarily going the way of a literal translation.

Perhaps reduction operators could accept an adverb to specify a closure to which the accumulator they implicitly hold (well, those that do!) is passed so that it can be used in a test to end the cycle, as in:

my $s = [~] :while({.length<1_000_000}) 1..*;

Replies are listed 'Best First'.
Re: [perl 6] re reduction operators
by TimToady (Parson) on Aug 30, 2007 at 15:44 UTC
    You could always use [\~] to return all of the intermediate results. Maybe
    my $s; for [\~] 1..* { last if .chars >= 1_000_000; $s := $_; }
    though it's not terribly functional to use temporary bindings like that. If we made optional parameters not "eat" values from the list then we could do a lookahead:
    my $s = first gather for [\~] 1..* -> $x, $y? { take $x if $y.chars >= 1_000_000; }
    or some such...
Re: [perl 6] re reduction operators
by ambrus (Abbot) on Aug 30, 2007 at 21:33 UTC

    It's sometimes easier to just join the numbers form 1 to 300000 and take the first 10^6 digits of that.

      It also helps to have a repl-loop so you can quickly try out how long the concatenation of 1..300000 takes and correct the number to a better approximation in a few steps.

      Well, that's what I would probably do if I had your skills and that interpreter. Still I'm interested in elegant and smart solutions that fit both in current Perl and in the much more interesting Perl 6 with its additional degrees of freedom. Of course Perl will never be an entirely mathematically oriented language, but if we can "improve" the situation, ain't it good anyway?

      BTW: sorry for replying so late. I've had and I'm still having very big troubles in real life which prevent me from writing all that I would want in virtual one. I was reminded of this long postponed followup by Re^2: [Perl 6] Even more freedom for custom operators?.