Pieces of Pi

13:36	shortcircuit	http://rosettacode.org/wiki/Pi
13:37	* shortcircuit	things Perl6 should implement that task as a sequence.
13:37	shortcircuit	*thinks

Well, can't turn down a challenge like that.

The task is to create a program to continually calculate and output the next digit of pi. The program should continue forever (until it is aborted by the user) calculating and outputting each digit in succession. The output should be a decimal sequence beginning 3.14159265 ...

First, research.

Ah, not only is it a cool project, but it is a chance to rework some Haskell code into Perl 6. Shiny!

So, it looks like the core of their approach is this function:

> stream :: (b->c) -> (b->c->Bool) -> (b->c->b) -> (b->a->b) -> 
>           b -> [a] -> [c] 
> stream next safe prod cons z (x:xs) 
>   = if safe z y 
>     then y : stream next safe prod cons (prod z y) (x:xs) 
>     else stream next safe prod cons (cons z x) xs 
>       where y = next z 

You know, some algorithms make more sense when they are made recursive. Maybe it's just because I'm not a hardcore functional programmer, but in this case recursion mostly serves to obfuscate the code. Here's my attempt to rewrite it in Perl 6:

sub stream(&next, &safe, &prod, &cons, $z is copy, @x is copy) {
    gather loop {
        my $y = next($z);
        if safe($z, $y) {
            take $y;
            $z = prod($z, $y);
        } else {
            $z = cons($z, @x.shift)
        }
    }
}

To my mind, even though this is longer, it's vastly clearer. There is one major problem, however: it doesn't actually work. That @x is copy there is not guaranteed to work when you pass in an infinite list; and the entire point of this routine is to pass in infinite lists! I don't know of a graceful way to handle this in Perl 6. This next works:

sub stream(&next, &safe, &prod, &cons, $z is copy, @x) {
    my $x-list = @x.iterator.list;
    gather loop {
        my $y = next($z);
        if safe($z, $y) {
            take $y;
            $z = prod($z, $y);
        } else {
            $z = cons($z, $x-list.shift)
        }
    }
}

It feels like there should be some more automatic way to do that in p6. Maybe something like "@x is ro-iterator"? (Yeah, that's an ugly name.)

Update: Ugly &s deleted from the sub bodies at moritz_++'s suggestion.

About these ads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

%d bloggers like this: