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 hill-climbing 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 hill-climbing 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
|