NAME
Grapefruit - Pattern matching and reduction engine for a perl CAS
SYNOPSIS
use Grapefruit;
print Solve( Equals( 5, Add( 3, x ) ), x );
DESCRIPTION
Just read the source, the comments try to be amusing. The only existing example code is in grapefruit.pl.
Grapefruit provides a pattern matching engine which will match against a parsetree of an expression. The parsetree (and pattern) is generated by small stub functions which create a Grapefruit::Compound object using their name and their arguments. They then pass this into the rule based reduction engine. A reduction engine, in contrast to a production engine where a set of rules are given for producing all the valid theorems of a system (to mix terminologies from parsing and Post's symbolic manipulation systems) , such as a Yacc or Parse::RecDescent grammar, has a set of rules (sorted by precendence in this implementation) each of which has a predicate, and a replacement parsetree. When the predicate (being passed a parsetree as its argument) is true, the parsetree is replaced by the one specified in the replacement. Portions of the parsetree being matched against can be 'captured' as in normal regular expressions, and can be substituted into the replacement tree. In Grapefruit, since parsetrees are generated as the return values of functions, the replacements are implemented as subroutine references which are called with the captures are arguments.
The idea is that the core of Grapefruit, the reduction engine, will stay very general and applicable to any application and that the ability to have different sets of rules will be aided by having a Grapefruit::Ruleset object. This means that since it's dependent on multimethods, namespace hell will avoided by being able to say $ruleset->import, to import all the symbols from your chosen ruleset or package (%pkg::RULES).
Another important part is the original aim of developing a computer algebra system in perl (and using perl, note the difference). There's two goals here, one is to create a cmdline application like yacas or maxima (and optionally a gui via TeXmacs or similar), and the other is to enable algebra in a normal perl program.
Here's some dream code from the distant future:
use Grapefruit::Algebra; # basic algebra rules and operators
use Grapefruit::Calculus::Differential; # the differential calculus, this is mainly here for fun
use Grapefruit::Algorithm::NewtonRaphson; # this includes the above
# they all export their rulesets by default; ie they have @ISA=qw(Grapefruit::Ruleset);
sub f {
my $x = shift;
return 5*$x**5+4*$x**4+5; # any takers for solving this by hand?
}
print Newton(\&f, 4); # this differentiates it for us!
Ok that wasn't very enlightening code, and all those imports weren't needed but it should serve as a goal to achieve.
BUGS
Now I'm using objects with overloaded operators I've got a nice problem with complex numbers. Because evaluation is no longer delayed we tend to end up with 'NaN'. I can't simply use Math::Complex because it doesn't play well with Math::BigFloat which is a potential problem for this module. I anticipate that I'll solve this in one of three ways: write my own complex implementation (which plays nicely with the whole system; turn all numbers into Grapefruit::Atoms possibly using constant overloading; write some code which detects which modules the user is using and adapt. None of this seems much fun. The second idea currently sounds the most feasible.
AUTHOR
Benjamin Smith <bsmith@cpan.org>, usually available as integral on the freenode irc network