Previous | Table of Contents | Next |
6.2.8.3. Some Subtleties of the Execution Model
The Prolog execution model as given is a simplification in several ways:
The algorithm as presented looks very inefficient because when substituting a variable by another term, we go through the rest of the query looking for all occurrences. Of course, real implementations dont do this. Rather, occurrences of variables are represented as pointers to structures, and only those structures are changed.
What about the output predicates write and nl that we met in section 6.2.1? These are handled by Prolog in a straightforward way: When a write or nl is the first atom in a query, the system simply does the output action and goes on evaluating the rest of the query. Consider the query member([a,b], X), write(Trying ), write(X), nl, X=b. The substitutions returned by Prolog are exactly the same as those in the example of section 6.2.8.1 because the output predicates have no effect on variables. The output of the query is
Trying a Trying b X = b ?
After the system backtracked to try the second clause of member again, it executed the write and nl atoms again, producing two outputs. The other I/O predicates of Prolog (which we will meet in section 6.3.5) behave in a similar way.
We can use these imperative features to debug programs in Prolog if we want. However, if your Prolog has an interactive debugger (the most common kind is described in section 6.3.8), it is probably better to use that because the output from a backtracking program is difficult to follow. It is better to use Prologs I/O system for interacting with the user.
This section deals with some of the most important advanced features of Prolog. The logic and control constructs we look at here include negation, the Prolog cut, the predicates for finding all solutions, and the predicates for manipulating the knowledge base. The forms of terms we explore include numeric terms, function-symbol terms, and strings. We also look at advanced usability features such as the Prolog interactive debugger, definite clause grammars, and operator declarations.
It is sometimes necessary to state not that a property holds, but that a property does not hold. Prolog provides the negation symbol \+ for doing this. \+ is a prefix operator that we can apply to any atom. For instance, if we want to find a term that is in the list [a,b] but not in the list [b,c], we can do so with the query
member([a,b], X), \+ member([b,c], X).
The only solution that Prolog returns is a because this is the only element of [a,b] that is not also an element of [b,c]. The \+ operator is of lower precedence than the comma that separates atoms in a goal, so it applies only to the next atom in a comma-separated sequence. Thus the query
member([a,b], X), \+ member([b,c], X), member([a], X).
would return the same thing. An atom or the negation of an atom is often referred to as a literal.
Previous | Table of Contents | Next |