A few days ago I started to again work on implementing predicate logic in Perl. I know it can be done. I just need that epiphany that makes me slap my forehead. I stopped working on the latest implementation because it was awful, but I kept thinking about the problem. Basically, to get anything similar to Prolog in Perl, I need backtracking. The only thing in Perl which implements backtracking is a regular expression. I'm pretty sure the key lies there.
This morning, I thought I had the epiphany. What if, given a set of facts, I would like to know who owns gold?
my $facts = <<END_FACTS;
owns merlyn gold
owns Ovid books
gives Ovid books kudra
owns kudra gold
END_FACTS
+
+
my $query = qr/owns (\S+) gold/;
my @who = $facts =~ /$query/mg;
That assigns "merlyn" and "kudra" to @who, but it's not really useful. What if I want the query to be something like "who owns something valuable?" I can do this:
use Data::Dumper;
use constant SUCCEED => qr{(?=)};
use constant FAIL => qr{(?!)};
+
+
my $owns = <<END_FACTS;
owns merlyn gold
owns Ovid books
owns kudra gold
END_FACTS
+
+
my $valuable = <<END_VALUABLE;
valuable Perl
valuable gold
valuable Corinna
END_VALUABLE
+
+
my $is_valuable = qr[(\S+)(??{match($valuable, "valuable $2")})];
my $owns_query = qr/owns (\S+) $is_valuable/;
# here's the magic!
my @who = $owns =~ /$owns_query/mg;
print Dumper \@who;
+
+
sub match {
my ($facts, $query) = @_;
my $sleep_count = 0;
my $pid;
do {
$pid = open KID_TO_READ, "-|";
unless (defined $pid) {
die "Couldn't fork" if $sleep_count++ > 6;
sleep 1;
}
} until defined $pid;
+
+
unless ($pid) { # child
if ($facts =~ $query) {
print SUCCEED;
}
else {
print FAIL;
}
}
else { # parent
my $result = <KID_TO_READ>;
close KID_TO_READ;
return $result;
}
}
The prints out:
$VAR1 = [
'merlyn',
'gold',
'kudra',
'gold'
];
That's great. Once I can autogenerate those regexes and clean up the output I can wrap this up in a pretty framework and do all of the predicate logic programming I want.
Uh, no I can't. Regular expressions are not reentrant, thus forcing me to fork off a new process for every regex "nested" inside of the main query (such as the "is_valuable" condition). This winds up being so ridiculously slow that it's probably not worth much more than a toy. I also suspect that a complicated query will suck memory like a Hoover. Any suggestions to get around this, or am I stuck?
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
Outside of code tags, you may need to use entities for some characters:
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.
|
|