At this point you should probably try using Prolog's
trace facilities, and see if you can follow what's
happening for examples like the one above. Trace
facilities may vary slightly from implementation to
implementation, but are all based on the same basic
control flow model, known as the box model.
Basically, for any prolog procedure (say, ancestor)
we can get Prolog to tell us when it calls that
procedure, when it exits (successfully) that
procedure, when it retries that procedure (because
of bactracking - sometimes indicated by back) and when it
finally fails that
procedure. You can specify the procedure of
interest by setting spy points, but for now
we will just look at the simplest kind of trace, where it
tells you about every procedure. In a typical Prolog we might have,
for example:
| ?- trace. yes | ?- ancestor(alison, Anc). (1) 1 call: ancestor(alison,_0) ? (2) 2 call: parent(alison,_0) ? (2) 2 exit: parent(alison,david) (1) 1 exit: ancestor(alison,david) X = david ; (1) 1 redo: ancestor(alison,_0) ? (2) 2 redo: parent(alison,_0) ? (2) 2 exit: parent(alison,kathleen) (1) 1 exit: ancestor(alison,kathleen) X = kathleen ; (1) 1 redo: ancestor(alison,_0) ? (2) 2 redo: parent(alison,_0) ? (2) 2 fail: parent(alison,_0) (3) 2 call: parent(alison,L103) ? (3) 2 exit: parent(alison,david) (4) 2 call: ancestor(david,_0) ? (5) 3 call: parent(david,_0) ? (5) 3 exit: parent(david,harold) (4) 2 exit: ancestor(david,harold) (1) 1 exit: ancestor(alison,harold) X = harold ;
Prolog first calls ancestor(alison, _0) (where \_0 is Prolog's internal variable name), and calls the subgoal, parent(alison, _0). This succeeds, so exits which results in ancestor(alison, _0) exiting with ancestor(alison, david). When bactracking is forced, Prolog retries ancestor(alison, _0), and starts by redoing parent(alison, _0), which exits with parent(alison, kathleen). ancestor(alison, _0) therefore also exits. Forcing backtracking again, Prolog retries (again) ancestor(alison, _0). Retrying parent(alison, _0) fails - there are no more facts matching this. So using the second ancestor rule it calls parent(alison, L103) (where L103 is an internal Prolog variable). This succeeds, so using the second subgoal of rule 2 it calls ancestor(david, _0). This succeeds (exits) with parent(david, harold), so the second call to ancestor exits, and so does the first.
Prolog trace facilities, while all looking something like the above, vary a fair amount between implementations. Eventually you will have to get to know the foibles and peculiarities of your favourite Prolog's trace facilities. For now, just try tracing a few simple predicates and see if you can follow what's going on.