AI::Perlog

Ovid on 2008-01-07T09:33:13

AI::Perlog is an experimental replacement of AI::Prolog that I have on my hard drive. I was thinking about it last night and realized that there are two things we really need for "logic" programming: unification and a search algorithm (typically implemented as a depth-first backtracking algorithm).

I already have the unification working. In AI::Prolog, you could only unify scalars or lists (I'm being very loose with terminology here). I think that sucks, so my version also allows unification of hashes and regular expressions. I also am thinking about code unification at some point, but not just yet.

Of course, this unification is recursive, so you can unify an array of hashes of hashes of arrays of hashes, if you want.

Now that this is working, I need to figure out the search algorithm. My first pass is going probably be a naive backtracking algorithm. Make it work, then make it fast. However, in order to do this, I need to figure out a clean syntax for adding rules. Right now, facts are like this:

use AI::Perlog;
my $data = AI::Perlog->new( {
    predicates => [qw/loves gives/],
} );
$data->add_facts(
  [qw/ loves Ovid perl /],
  [qw/ loves hippies peace harmony /],         # variadic predicates
  [qw/ loves hippies /, [qw/peace harmony/] ], # arrays
  [qw/ loves john /, { 
    wife      => 'Mary', 
    boyfriend => 'Larry', # oops
  } ],                                         # hashes
  [qw/ loves Ovid Perl6 /],
  [qw/ loves Andy beer /],
  [qw/ gives W grief world /],
);
my @results = $data->query( 'loves', undef, qr/^(?i:perl)6?$/ );

In other words, that will tell you everyone who loves some variant of Perl.

There are a few flaws with this interface (suggestions welcome!). The first I need to fix is that undef in the query. That needs to be a logic variable which is automatically bound. That might look like this (borrowed from Luke Palmer's Logic module):

var my $who;
my $query = $data->query( 'loves', $who, qr/^(?i:perl)6?$/ );
while ( $query->() ) {
    print "$who\n";
}

Second, query needs to return a lazy iterator (perhaps with the above syntax).

Third, I need a clean syntax for rules. For example, consider the following rule in Prolog:

gives(tom, book, SOMEONE) :-
    person(SOMEONE),
    likes(tom, SOMEONE).

That query says "tom will give a book to someone if that someone is a person and tom likes them." How would I express that in a pure perl way that's clean and intuitive? That's a bit of a challenge. Regrettably, while I have the unification, I won't have the search algorithm until I figure out a clean interface. That shouldn't be a problem, but I can't help but focus on this bit right now.

The major advantage of this module over AI::Prolog is that there's no secondary programming language to learn. This means that you can just focus on the logic programming, but it also means that you're not limited by Prolog's constraints.

I also think that it needs to be written up front to return sets and not bags. This will likely slow things down quite a bit, but returning bags isn't logically correct, while returning sets is. Still, the implementation I have in mind has a fair amount of overhead and logic programming in Perl is slow enough as is.