Thinking about embedding constraints in perl

jjore on 2007-01-02T20:24:35

I'd like to integrate a logic engine into normal imperative perl with some reasonable ergonomics. This is all sugar for getting to AI::Prolog. It's just an experiment with myself about how to allow normal code to use the benefits of logic programming.

The primary benefits I'm interested in are abstracting away the search code, parameterizing the search strategy, and simplicity of maintenance.

A package may have a database of rules, variables, bindings, whatever. It's just a package variable or something like that.

Logic variables get tied because they were tagged with an attribute like :Logic or something. Interacting with the variables means assertions get stored or tested in the database.

I'm in the middle of learning Mozart which does this kind of thing and then I probably ought to go learn how Mercury parameterizes its search strategies.

package Somewhere;
# Hoist 'RULES' block to be executed like BEGIN or similar
RULES {
    # RULES GO HERE
    $bar == $foo;
}

sub foo { $bar = 42;

RULES { # These rules are present for this scope? $baz == $quux; }

return $foo; # returns 42 }


Rethinking Prolog

Ovid on 2007-01-02T22:35:01

Part of the reason I'm glad that they didn't try to shoehorn logic programming into Perl 6 is the following:

father(jim,bob).
father(bob,sean).
mother(alice,bob).
mother(alice,mary).
mo ther(mary,sally).
parent(P,C) :-
    father(P,C);
    mother(P,C).
siblings(S1,S2) :-
    parent(P,S1),
    parent(P,S2),
    S1 \= S2.
cousin(X,Y) :-
    parent(P1,X),
    parent(P2,Y),
    siblings(P1,P2).

Now ask any version of Prolog who cousins are:

?- consult('family.pro').
% family.pro compiled 0.00 sec, 1,816 bytes

Yes
?- cousin(X,Y).

X = sean
Y = sally ;

X = sally
Y = sean

Yes
?-

Whee! We have the same logical problem that we routinely get with SQL: results are bags, not sets, and thus can cause all sorts of difficulties for programmers. In fact, if you troll through Prolog posts on message boards, read through homework assignments, or just check comp.lang.prolog, the question which keeps popping up time and time again is "why am I getting duplicates?" Of course, once you understand how Prolog's search strategy works, the duplicates are obvious, but the problem is, they're useless. They're just telling you the same thing more than once. I fear Perl 6 would suffer the same problems.

Of course, you can write routines (as Prolog programmers often do) to cull the duplicates, but they often suffer bugs because, as you can see from the above example, we even have the correct data bound to different variables in the duplicates. That makes culling duplicates a serious problem, even though this would be a non-issue if Prolog returned sets instead of bags. In SQL this is avoided via "SELECT DISTINCT", so at least it's easy to work around, but bags shouldn't be returned in the first place because it's terribly easy to return bags and get incorrect answers (like when you're counting how many results satisfy a certain rule).

I love Prolog because it's so frickin' easy and it makes some hard problems really simple to deal with, but like most declarative programming implementations I've stumbled across, it doesn't return logically correct answers, it returns algorithmically correct answers which, when reduced to sets, are logically correct.

Side note: if you want a pure Perl version of this problem using regular expressions, tell me an "easy" way of getting rid of duplicates with the following (thing of Prolog's append/3) :)

use re 'eval';
my $string = "abc";
my $length = length $string;
my $regex  = qr/(\G[$string]{0,$length}(?{print "# [$&][$'][$string]\n"}))/ x 2;
$string =~ $regex;

(Caching and filtering results is cheating because you're still doing all of the work up front and just hacking the results rather than correcting the underlying flaw).

Also, Prolog math is not logical. You can't simply use this the way you might think:

convert(Celsius, Fahrenheit) :-
    Celsius is (Fahrenheit - 32) * 5 / 9.

You can solve convert(C, 50), but not convert(50, F), because Prolog can't solve the RHS without Fahrenheit being bound. I do understand that there are work-arounds to many of these problems and if you stumble across a logic programming system which handles these natively with a clean algorithm, I've love to see it.

Oops!

Ovid on 2007-01-02T22:36:50

I forgot to mention that, ignoring everything I wrote above, I'd still love to see this!