0

I just realized that was a dumb question. Curious if anyone can still find a loophole though.

Source code:

married(trump,obama).
married(trump,goat).
married(pepee,pepper).
married(X,Y) :- married(Y,X),!. % not awesome because of infinite recursion

Goal: ex. married(trump, putin).
trace(
first base case fails.
second base case fails.
third base case fails.
married(trump,putin) = married(putin,trump),!.

what I want it doing is try married (putin,trump) again but all earlier base cases will fail again. We tried switching args before and failed. So don't recurse. Just return false.

I get a stack error because until married(putin,trump) or other way around before ! will never return true or false so cut will not be able triggered.

Easier and more sane way is to just rewrite the code to prevent recursion. I'm curious if there is a way to try switching args once and return fail if that fails. If u have a long list of facts, u can reduce that long list by half if u can try arg1,arg2 and vice versa. Potentially more exponentially if we get crazy permutation scenarios.

Any insights will be awesome thanks.

repeat
  • 18,496
  • 4
  • 54
  • 166
John Doe
  • 55
  • 1
  • 2

1 Answers1

4

You are on the right track with "switching args once and return fail if that fails", even though that is worded very imperatively and does not cover all modes we expect from such a relation.

For this to work, you need to separate this into two predicates. It is easy to show that a single predicate with the given interface is not sufficient.

First, the auxiliary predicate:

married_(a, b).
married_(c, d).
etc.

Then, the main predicate, essentially as you suggest:

married(X, Y) :- married_(X, Y).
married(X, Y) :- married_(Y, X).

Adding impurities to your solution makes matters worse: Almost invariably, you will destroy the generality of your relations, raising the question why you are using a declarative language at all.

Example query:

?- married(X, Y).
X = a,
Y = b ;
X = c,
Y = d ;
X = b,
Y = a ;
X = d,
Y = c.

Strictly speaking, you can of course also do this with only a single predicate, but you need to carry around additional information if you do it this way.

For example:

married(_, a, b).
married(_, c, d).
married(first, X, Y) :- married(second, Y, X).

Example query:

?- married(_, X, Y).
X = a,
Y = b ;
X = c,
Y = d ;
X = b,
Y = a ;
X = d,
Y = c.

This closely follows the approach you describe: "We tried switching args before. So don't do it again."

mat
  • 40,498
  • 3
  • 51
  • 78
  • Thanks for the comment, mat. This is what I ended up doing. I put another helper function just before triggering this family function with cut feature to prevent triggering this function altogether if non-family member pairs are given. It's a bandit solution since it doesn't solve the fundamental flaw of this relation but it will suffice. Another better way is to simply not use recursion because let's face it, recursion that performs recursion once is like telling an Olympic champion is to run really fast with only one step. marriageCheck(X,Y) :- (married(X,Y) ; married(Y,X)). – John Doe Mar 22 '17 at 18:14
  • This last version you show is equivalent to the first version I posted: I used two clauses to represent the alternatives, and you are using `(';')/2`, which also denotes logical alternatives and can be used as an alternative for clauses. Note though that this predicate is very general (which is good!), and can be used not only to *check*, but also to *generate* and *complete* solutions. Therefore, `marriageCheck` is a misnomerAndAlsoQuiteHardToReadIMustSaySinceItMixesTheCases. – mat Mar 22 '17 at 18:31
  • Seems like. I wonder (can't run prolog atm) what would happen after query finishes. It seems like all previous facts will have to be rewritten (since married function takes two args whereas ur married function takes 3). But let's assume that wasn't an issue. trace it with me here.. tries all facts, then we hit married(first,X,Y) :- married(second,Y,X). it scans all facts again with (second,Y,X). if that fails as well we run into married (second,Y,X) V :- married(second,Y,X). what would happen here? I can't trace in my mind;. they are the same so.. stops there? – John Doe Mar 22 '17 at 23:38
  • You have everything right until the following: "... we run into `married(second, Y, X)`". There is **no** such clause! Please note that the clause head has `first` as its first argument. On the second try, the first argument of the goal is consciously specified as `second`. For this reason, the clause *no longer applies* because `dif(first, second)`. For this reason, the clause is *not* tried again. To simplify, post the following query: `?- married(second, X, Y).` and see that the last clause *does not apply*. – mat Mar 22 '17 at 23:42
  • I'm in a wrong field. Ugh. That's right. Good call. – John Doe Mar 23 '17 at 02:51