#!/usr/bin/ruby

#
## A very basic Fraction() class, implementing a few symbolic relations.
#

class Fraction(num, den) {

    method +(Number o) {
        self + Fraction(o, 1)
    }

    method +(Fraction o) {
        Fraction(
            num*o.den + o.num*den,
            den*o.den
        )
    }

    method -(Number o) {
        self + -o
    }

    method -(Fraction o) {
        self + -o
    }

    method *(Number o) {
        Fraction(num*o, den)
    }

    method *(Fraction o) {
        Fraction(num*o.num, den*o.den)
    }

    method /(Number o) {
        Fraction(
            num,
            den * o
        )
    }

    method /(Fraction o) {
        Fraction(
            num * o.den,
            den * o.num,
        )
    }

    method **(Number o) {
        if (o < 0) {
            var a = o.abs
            Fraction(den**a, num**a)
        }
        else {
            Fraction(num**o, den**o)
        }
    }

    method neg {
        Fraction(-num, den)
    }

    method to_s {
        "Fraction(#{num}, #{den})"
    }
}

class Number {
    method +(Fraction o) {
        o + self
    }

    method -(Fraction o) {
        -o + self
    }

    method *(Fraction o) {
        o * self
    }

    method /(Fraction o) {
        o**(-1) * self
    }
}

var r = 42+Fraction(3,4)

assert_eq(r.num, 171)
assert_eq(r.den, 4)
assert_eq(42 + 3/4, r.num/r.den)

r = 42*Fraction(3, 4)
assert_eq(r.num, 42*3)
assert_eq(r.den, 4)

r = 1/Fraction(3,4)
assert_eq(r.num, 4)
assert_eq(r.den, 3)

r = 12-Fraction(3, 4)
assert_eq(r.num, 45)
assert_eq(r.den, 4)

#
## sum(f(n)) = e, as n->oo.
#
func f((0)) { Fraction(1, 1) }
func f(n)   { f(n-1) / n     }

assert_eq(f(10).den, 10!)

func num(n) {      (-1)**n }
func den(n) { (2*n + 1)**2 }

#
## sum(num(n)/den(n)) = Catalan's constant, as n->oo.
#
var sum
for i in (0 .. 5) {
    var f = Fraction(num(i), den(i))
    defined(sum) ? (sum += f) : (sum = f)
    say sum
}

assert_eq(sum.num, 98607816)
assert_eq(sum.den, 108056025)