sub zeta($s) { [\+] map -> \n { 1 / n**$s }, 1..* }
say zeta(2)[1000];
####
sub infix:<+>(Irrational $x, Irrational $y) {
Irrational.new: gather while True {
(state $n)++;
take $x[$n] + $y[$n];
}
}
####
sub infix:<==>(Irrational $x, Irrational $y) {
while True {
(state $n)++;
return $x[$n] == $y[$n];
}
}
####
package Real;
# the accuracy number below is only for display.
# It does not affect the (infinite) precision of the numbers.
our $accuracy = 1e-3;
use overload '+' => sub {
my ($a, $b) = map { $_->() } my ($x, $y) = @_;
bless sub { sub { $a->() + $b->() } }, ref $x;
},
'*' => sub {
my ($a, $b) = map { $_->() } my ($x, $y) = @_;
bless sub { sub { $a->() * $b->() } }, ref $x;
},
q{""} => sub {
my $x = shift->();
my $a = $x->();
my $b;
while (abs($a - ($b = $x->())) > $accuracy) {
$a = $b;
}
return "$b (±$accuracy)";
},
;
1;
package Test;
my $one = bless sub { sub {1} }, 'Real';
sub Exp {
my $x = shift;
bless sub {
# Here I use floating points for convenience
# but obviously I should use only rationals.
my ($s, $p, $n) = (1, 1, 1);
sub { $s += $p *= $x / $n++ }
}, 'Real';
}
sub Arctan {
my $x = shift;
bless sub {
# same remark here about the use of floating points
my ($s, $p, $n) = (0, 1, -1);
sub { $s += (-1)**++$n * ($p *= $x) / (2*$n + 1) }
}, 'Real';
}
print $one, "\n";
print my $two = $one + $one, "\n";
print my $three = $two + $one, "\n";
print my $e = Exp(1), "\n";
print $e + $one, "\n";
print $e * $e, "\n";
print ($three + $one) * Arctan(1);