Rat Catcher

So, onward to addition. Here’s Rakudo’s code for adding two Rats:

multi sub infix:<+>(Rat $a, Rat $b) {
    my $gcd = pir::gcd__iii($a.denominator, $b.denominator);
    ($a.numerator * ($b.denominator div $gcd) + $b.numerator * ($a.denominator div $gcd))
        / (($a.denominator div $gcd) * $b.denominator);

And here’s my first stab at a translation to Math::FatRat (named FR+ because of the issues discussed in my last post):

    multi sub infix:<FR+>(Math::FatRat $a, Math::FatRat $b) is export(:DEFAULT) {
        my $gcd = gcd($a.denominator, $b.denominator);
        Math::FatRat.new($a.numerator * ($b.denominator div $gcd) + $b.numerator * ($a.denominator div $gcd),
                         ($a.denominator div $gcd) * $b.denominator);

The big difference here is calling Math::FatRat.new instead of infix:</> for object construction. You might think we could define an infix:</> that took two Math::BigInt objects, but that would move our code away from our goal of being as close as possible to the Perl 6 spec (because infix:</> can never turn Ints to a FatRat).

My next step was to think about adding a FatRat and a Rat. Here’s what the code would look like:

    multi sub infix:<FR+>(Math::FatRat $a, Rat $b) is export(:DEFAULT) {
        my $gcd = gcd($a.denominator, $b.denominator);
        Math::FatRat.new($a.numerator * ($b.denominator div $gcd) + $b.numerator * ($a.denominator div $gcd),
                         ($a.denominator div $gcd) * $b.denominator);

Notice something about this? Other than the signature, this code is exactly the same. (Warning: at the moment, the gcd function actually cannot handle Ints, but it clearly should.) This got me thinking about ways to avoid duplication.

    multi sub infix:<FR+>(Rat | Math::FatRat $a, Rat | Math::FatRat $b) is export(:DEFAULT)

is not actually legal Perl 6. But you could do this

    multi sub infix:<FR+>($a where Rat | Math::FatRat, $b where Rat | Math::FatRat) is export(:DEFAULT)

That still seem inelegant. Wonder what the Perl 6 spec says about this?

Well, the spec has a Rational role! It’s not in Rakudo yet, but when it is, you’ll be able to write something like this:

    multi sub infix:<FR+>(Rational $a, Rational $b) is export(:DEFAULT) {
        my $gcd = gcd($a.denominator, $b.denominator);
        Math::FatRat.new($a.numerator * ($b.denominator div $gcd) + $b.numerator * ($a.denominator div $gcd),
                         ($a.denominator div $gcd) * $b.denominator);

(I think: Rational is described as a parameterized role, and I admit I’m not quite clear on how to use them.) (And the situation is more complicated than that, because there are envisioned to be all sorts of Rational types, and it’s not clear to me exactly how one can figure out which brand of Rational the result object should be.)

Errr… I was going to launch into a second half on this post, but I just realized it’s already pretty long, so I will talk about gcd and simplifying fractions in my next post.

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


Get every new post delivered to your Inbox.

%d bloggers like this: