Logic Languages
Prev: Functional Languages Next: Concurrency
12.1-12.2 Check Your Understanding
- What mathematical formalism underlies logic programming?
- What is a Horn clause?
- Briefly describe the process of resolution in logic programming.
- What is a unification? Why is it important in logic programming?
- What are clauses, terms, and structures in Prolog? What are facts, rules, and queries?
- Explain how Prolog differs from imperative languages in its handling of arithmetic.
- Describe the difference between forward chaining and backward chaining. Which is used in Prolog by default?
- Describe the Prolog search strategy. Discuss backtracking and the instantiation of variables.
12.2.6-12.4 Check Your Understanding
- Explain the purpose of the cut (
!) in Prolog. How does it relate to\+? - Describe three ways in which Prolog programs can depart from a pure logic programming model.
- Describe the generate-and-test programming idiom.
- Summarize Prolog’s facilities for database manipulation. Be sure to mention
assert,retract, andclause. - What sorts of logical statements cannot be captured in Horn clauses?
- What is the closed world assumption? What problems does it cause for logic programming?
12.6 Exercises
- Starting with the clauses at the beginning of Example 12.17, use resolution, as illustrated in Example 12.3, to show, in two different ways, that there is a path from
atoe. - Solve Exercise 6.22 in Prolog.
- Consider the Prolog gcd program in Figure 1.2. Does this program work “backward” as well as forward? Given integers
dandn, can you use it to generate a sequence of integersmsuch thatgcd(n, m) = d? Explain your answer. - In the spirit of Example 11.20, write a Prolog program that exploits backtracking to simulate the execution of a nondeterministic finite automaton.
- Show that resolution is commutative and associative. Specifically, if
A,B, andCare Horn clauses, show that(A ⊕ B) = (B ⊕ A)and that((A ⊕ B) ⊕ C) = (A ⊕ (B ⊕ C)), where⊕indicates resolution. Be sure to think about what happens to variables that are instantiated as a result of unification. - In Example 12.8, the query
?- classmates(jane_doe, X)will succeed three times: twice withX = jane_doeand once withX = ajit_chandra. Show how to modify theclassmates(X, Y)rule so that a student is not considered a classmate of himself or herself. - Modify Example 12.17 so that the goal
path(X, Y), for arbitrary already-instantiatedXandY, will succeed no more than once, even if there are multiple paths fromXtoY. - Using only
\+and no cuts, modify the tic-tac-toe example of Section 12.2.5 so it will generate only one candidate move from a given board position. How does your solution compare to the cut-based one in Example 12.22? - Prove the claim, made in Example 12.19, that there is no winning strategy in tic-tac-toe, that either player can force a draw.
- Prove that the tic-tac-toe strategy of Example 12.19 is optimal, wins against an imperfect opponent whenever possible, draws otherwise, or give a counterexample.
- Starting with the tic-tac-toe program of Figure 12.4, draw a directed acyclic graph in which every clause is a node and an arc from
AtoBindicates that it is important, either for correctness or efficiency, thatAcome beforeBin the program. Do not draw any other arcs. Any topological sort of your graph should constitute an equally efficient version of the program. Is the existing program one of them? - Write Prolog rules to define a version of the
memberpredicate that will generate all members of a list during backtracking, but without generating duplicates. Note that the cut- and\+-based versions of Example 12.20 will not suffice; when asked to look for an uninstantiated member, they find only the head of the list. - Use the
clausepredicate of Prolog to implement thecallpredicate, pretending that it is not built in. You needn’t implement all of the built-in predicates of Prolog; in particular, you may ignore the various imperative control-flow mechanisms and database manipulators. Extend your code by making the database an explicit argument tocall, effectively producing a metacircular interpreter. - Use the
clausepredicate of Prolog to write a predicatecall_bfsthat attempts to satisfy goals breadth-first. Hint: You will want to keep a queue of yet-to-be-pursued subgoals, each of which is represented by a stack that captures backtracking alternatives. - Write a list-based insertion sort algorithm in Prolog. Here’s what it looks like in C, using arrays:
void insertion_sort(int A[], int N)
{
int i, j, t;
for (i = 1; i < N; i++) {
t = A[i];
for (j = i; j > 0; j--) {
if (t >= A[j-1]) break;
A[j] = A[j-1];
}
A[j] = t;
}
}- Quicksort works well for large lists, but has higher overhead than insertion sort for short lists. Write a sort algorithm in Prolog that uses quicksort initially, but switches to insertion sort, as defined in the previous exercise, for sublists of 15 or fewer elements. Hint: You can count the number of elements during the partition operation.
- Write a Prolog sorting routine that is guaranteed to take
O(n log n)time in the worst case. Hint: Try merge sort; a description can be found in almost any algorithms or data structures text. - Consider the following interaction with a Prolog interpreter:
?- Y = X, X = foo(X).
Y = foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(
foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(
foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(
foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(
foo(foo(foo(foo(foo(foo(...What is going on here? Why does the interpreter fall into an infinite loop? Can you think of any circumstances, presumably not requiring output, in which a structure like this one would be useful? If not, can you suggest how a Prolog interpreter might implement checks to forbid its creation? How expensive would those checks be? Would the cost in your opinion be justified?
19. 12.19-12.21 In More Depth.