2

I'd like to understand why the interaction with swipl appears to be inconsistent.

Here's a typical example. Suppose I have consulted a knowledgebase that includes the following definitions:

acc_max([H|T], A, Max) :- H  > A, acc_max(T, H, Max).
acc_max([H|T], A, Max) :- H =< A, acc_max(T, A, Max).
acc_max([], A, A).

max([H|T], Max) :- acc_max(T, H, Max).

Below I show what my screen looks like after I type max([0, 1, 2], X). at the prompt, and hit Enter:

?- max([0, 1, 2], X).
X = 2 ▮

(The indicates the position of the cursor.)

Note, in particular, that the interpreter's next prompt has not yet appeared.

Here's what the screen looks like after I type ;:

?- max([0, 1, 2], X).
X = 2 ;
false.

?- ▮

Now I finally get the interpreter's prompt.

In contrast, below I show what my screen looks like after I type max([2, 0, 1], X). at the prompt, and hit Enter:

?- max([2, 0, 1], X).
X = 2.

?- ▮

Notice that this time I got the interpreter's prompt right away - I did not need to type ;. Also, there's no false.

I've found many other similar inconsistencies (e.g. sometimes the output true. shows up on the screen, but in other similar situations it doesn't).

As a newcomer to Prolog, I find such inconsistencies disconcerting (not to mention discouraging, since they are a constant reminder that I really have no clue of what's going on).

Is there a simple way to rationalize these inconsistencies?

Alternatively, is there some implementation of Prolog that provides a more consistent and predictable interaction than does SWI-Prolog?

false
  • 10,264
  • 13
  • 101
  • 209
kjo
  • 33,683
  • 52
  • 148
  • 265
  • 3
    This has to do with "choice points" in Prolog. In your first example, because of the order in which it found solutions relative to your input, Prolog had a choice point to explore after presenting the solution `X = 2`, so it searched for more but found no more solutions to the query. In your second case, the `X = 2` was determined and there were no choice points. – lurker Mar 01 '17 at 02:06

1 Answers1

5

So, as @lurker said, this is the result of choice points - cases where there is a rule that has not been evaluated, which may yield more solutions.

Let's go through an even simpler version of your example, max([0,1],X). vs max([1,0],X)..

max([0,1],X).:

This goes to acc_max([1],0,X)., which matches both acc_max([H|T], A, Max) :- rules. We evaluate them in the order that they appear:

First we see that 1 > 0 is true, and call acc_max([],1,X). This matches only acc_max([], A, A)., and we therefore unify X with 1. We have a solution! But we also have a rule that has not been evaluated yet. This is where you see:

X = 1 ▮

So now we type ;, and evaluate the second acc_max([H|T], A, Max) :- rule. We see that 1 =< 0 is not true, so this rule fails. We are now out of rules to try, so it turns out there are no more solutions. Hence:

X = 1 ;
false.

Now we'll look at max([1,0],X).:

This is now acc_max([0],1,X).. Again, we have two rules, evaluated in the order they appear:

First we see that 0 > 1 is not true, so the first rule fails and we evaluate the second.

Now we see that 0 =< 1 is true, and call acc_max([],1,X). This matches only acc_max([], A, A)., and we therefore unify X with 1 (again). We have the solution, and this time we have no unevaluated rules (ie. no unexplored choice points). So now we see:

X = 1.

... as there is no doubt in Prolog's "mind" that there are no other solutions. If you were to invert the order of the rules:

acc_max([], A, A).
acc_max([H|T], A, Max) :- H =< A, acc_max(T, A, Max).
acc_max([H|T], A, Max) :- H  > A, acc_max(T, H, Max).

... you would see the behaviour invert as well.

Hopefully this helps to demonstrate that this is a consistent and predictable interaction, and should be one shared by all variants of Prolog.

Jim Ashworth
  • 765
  • 6
  • 17
  • 2
    Excellent answer, especially the last paragraph. An important property of this toplevel behaviour is that it easily lets you detect **unintended** choice points, even if there are no further solutions! This is important because choice points prevent certain optimizations, and of course also do not come for free themselves. In that regard, the current SWI behaviour is a huge improvement over what it previously had. – mat Mar 01 '17 at 10:22
  • You should change your `X = 2`s into `X = 1` in your examples, since your example does not contain 2. – Fatalize Mar 01 '17 at 10:24
  • @Fatalize - thanks! Lazy copy pasta error, whoops. My Xs are no longer 2s. – Jim Ashworth Mar 01 '17 at 10:26
  • You still have one left ;) – Fatalize Mar 01 '17 at 10:27
  • Le sigh - serves me right for hurrying before a meeting – Jim Ashworth Mar 01 '17 at 11:00