0

Assume someone wrote the following huge list of clauses:

loves(me, wife).
loves(me, dog).
loves(wife, dog).
hates(me, enemy).
attracts(iron, magnet).
...

Now I want to automatically generate reciprocal clauses given some higher-order predicate and rule similar to:

reciprocal([loves, hates, attracts, ...]).
some_conclusion :- some_premises.

so that I have the following expected result:

?- loves(wife, me).
true.

To keep things simple, I ignored the list argument and instead defined the simple clause reciprocal(loves). with some complex rule using reciprocal(X), but I can't seem to assert a rule with success.

I've tried different variations and orderings of

assert(
    Y :- (reciprocal(P), Y =.. [P, B, A], X =.. [P, A, B], call(X))
).

or (to add the deduced clauses themselves)

assert(Y), reciprocal(P), Y =.. [P, B, A], X =.. [P, A, B], call(X)

but I've only got false or errors like Arguments are not sufficiently instantiated using SWI-Prolog.

My question is (obviously): how can I make this rule work? I don't care whether the rule is part of the database or just a preprocessor to add the actual clauses to the database (although the former would be preferable), I just want to learn how to reason about predicates (i.e. how to use higher-order predicates).

Note: I've learned logic programming since a month only, and I want to try out some ideas from Notation3 and N-triples etc.


EDIT:

The missing part, the absolute cherry on the cake, is some dynamic solution using a rule similar to

Y :- (reciprocal(P), call(P, A, B), Y =.. [P, B, A]).

If anyone has some solution for this one, please post it!

  • First, try to get acquainted with `call/N` with `N > 1`. For example you may replace `X =.. [P, A, B], call(X)` by `call(P, A, B)` &ct – false Dec 26 '19 at 18:04

1 Answers1

0

I found the way to add clauses one by one to the database as such (MVP):

?- [user].
|: loves(me, wife).
|: loves(me, dog).
|: loves(wife, dog).
|: reciprocal(loves).
|: (Ctrl-Z)

?- dynamic loves/2   %! seems necessary for next clause...
true.

?- reciprocal(P), X =.. [P, A, B], Y =.. [P, B, A], assert(X :- (Y, !)).
P = loves,
X = loves(A, B),
Y = loves(B, A).

?- loves(wife, me).
true.

It seems I didn't arrange the 'rule' in this way which is procedurally sound.

Now I'll focus on findall to avoid requiring user input (the ; after each solution for P).


EDIT:

I completed all but one feature... Given a file db.pl containing

loves(me, wife).
loves(me, dog).
loves(wife, dog).
attracts(iron, magnets).

and a file rules.pl containing

reciprocal([
    loves,
    attracts
]).
parse_reciprocal([]).
parse_reciprocal([H|T]) :- 
    X =.. [H, A, B], Y =.. [H, B, A], dynamic(H/2), assert(X :- (Y, !)),
    parse_reciprocal(T).

:- initialization reciprocal(L), parse_reciprocal(L).

I succeed at my first goal

?- [db].
true.

?- [rules].
true.

?- loves(dog, wife).
true.

?- attracts(magnets, iron).
true.

The missing part, the absolute cherry on the cake, is some dynamic solution using a rule similar to

Y :- (reciprocal(P), call(P, A, B), Y =.. [P, B, A]).