role Node;
class Conjunction with Node {
has left => (is => 'ro', does => 'Node');
has right => (is => 'ro', does => 'Node');
}
class Disjunction with Node {
has left => (is => 'ro', does => 'Node');
has right => (is => 'ro', does => 'Node');
}
class Negation with Node {
has negated_term => (is => 'ro', does => 'Node');
}
class Primative with Node {
has label => (is => 'ro', isa => Str);
}
my $fred = Primative>new(label => "Fred");
my $john = Primative>new(label => "John");
my $fred_and_john = Conjunction>new(left => $fred, right => $john);
...;
Then I'd write a few "visitor" rules that can take a tree and tweak it, for example, finding a candidate for rewriting under De Morgan's laws...
my $demorgans_laws = sub
{
my $tree = $_[0];
if ($tree>isa('Conjunction')
and $tree>left>isa('Negation')
and $tree>right>isa('Negation'))
{
return Negation>new(
node => Disjunction>new(
left => $tree>left>negated_term,
right => $tree>right>negated_term,
),
);
}
if ($tree>isa('Disjunction')
and $tree>left>isa('Negation')
and $tree>right>isa('Negation'))
{
return Negation>new(
node => Conjunction>new(
left => $tree>left>negated_term,
right => $tree>right>negated_term,
),
);
}
return $tree;
};
Then use some kind of hillclimbing algorithm to apply the tweaking rules to the tree, creating new trees; discarding trees that become more complex than the original, and retaining trees that become simpler, or at least as simple.
The problem with hillclimbing is that you can find local maxima. If you're climbing a mountain, sometimes you find a small peak, and you need to climb downwards a bit before you can reach the true summit. This is a hard problem to solve without ending up with a completely undirected search. But luckily, it's a problem that many smart people have thought about, so there's a wealth of ideas on how to solve it if you delve into AI literature.
use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow>new>name
