Вы находитесь на странице: 1из 8

Q1. Factorial of a number.

The first of these definitions is:


factorial(0,1). factorial(N,F) :N>0, N1 is N-1, factorial(N1,F1), F is N * F1.

Total Mark: 5

This program consists of two clauses. The first clause is a unit clause, having no body. The second is a rule, because it does have a body. The body of the second clause is on the right side of the ':-' which can be read as "if". The body consists of literals separated by commas ',' each of which can be read as "and". The head of a clause is the whole clause if the clause is a unit clause, otherwise the head of a clause is the part appearing to the left of the colon in ':-'. A declarative reading of the first (unit) clause says that "the factorial of 0 is 1" and the second clause declares that "the factorial of N is F if N>0 and N1 is N-1 and the factorial of N1 is F1 and F is N*F1". The Prolog goal to calculate the factorial of the number 3 responds with a value for W, the goal variable:
?- factorial(3,W). W=6

Consider the following clause tree constructed for the literal 'factorial(3,W)'. As explained in the previous section, the clause tree does not contain any free variables, but instead has instances (values) of variables. Each branching under a node is determined by a clause in the original program, using relevant instances of the variables; the node is determined by some instance of the head of a clause and the body literals of the clause determine the children of the node in the clause tree.

All of the arithmetic leaves are true by evaluation (under the intended interpretation), and the lowest link in the tree corresponds to the very first clause of the program for factorial. That first clause could be written

factorial(0,1) :- true.

and, in fact, ?- true is a Prolog goal that always succeeds (true is built-in). For the sake of brevity, we have not drawn 'true' leaves under the true arithmetic literals. The program clause tree provides a meaning of the program for the goal at the root of the tree. That is, 'factorial(3,6)' is a consequence of the Prolog program, because there is a clause tree rooted at 'factorial(3,6)' all of whose leaves are true. The literal 'factorial(5,2)' is, on the other hand, not a consequence of the program because there is no clause tree rooted at 'factorial(5,2)' having all true leaves. Thus the meaning of the program for the literal 'factorial(5,2)' is that it is false. In fact,
?- factorial(3,6). yes ?- factorial(5,2). no

as expected. Clause trees are so-called AND-trees, since, in order for the root to be a consequence of the program, each of its subtrees must also be rooted at literals which are themselves consequences of the program. We will have more to say about clause trees later. We have indicated that clause trees provide a meaning or semantics for programs. We will see another approach to program semantics in Chapter 6. Clause trees do provide an intuitive, as well as a correct, approach to program semantics. We will need to distinguish between the program clause trees and so-called Prolog derivation trees. The clause trees are "static" and can be drawn for a program and goal regardless of the particular procedural goal-satisfaction mechanism. Roughly speaking, the clause trees correspond to the declarative reading of the program. Derivation trees, on the other hand, take into account the variable-binding mechanism of Prolog and the order that subgoals are considered. A trace of a Prolog execution also shows how variables are bound in order to satisfy goals. The following sample shows how a typical Prolog tracer is turned on and off.
?- trace. % The debugger will first creep -- showing everything (trace). yes [trace] ?- factorial(3,X). (1) 0 Call: factorial(3,_8140) ? (1) 1 Head [2]: factorial(3,_8140) ? (2) 1 Call (built-in): 3>0 ?

(2) 1 Done (built-in): 3>0 ? (3) 1 Call (built-in): _8256 is 3-1 ? (3) 1 Done (built-in): 2 is 3-1 ? (4) 1 Call: factorial(2, _8270) ? ... (1) 0 Exit: factorial(3,6) ? X=6 [trace] ?- notrace. % The debugger is switched off yes

The title of this section referred to two factorial definitions. Here is the other one, with the same predicate name, but using three variables.
factorial(0,F,F). factorial(N,A,F) :N > 0, A1 is N*A, N1 is N -1, factorial(N1,A1,F).

For this version, use the following type of a goal:


?- factorial(5,1,F). F=120

The second parameter in the definition is a so called an accumulating parameter. This version is properly tail recursive. It is very important for the student to complete the following exercises. Exercise 1.1. Using the first factorial program, show explicitly that there cannot possibly be an clause tree rooted at 'factorial(5,2)' having all true leaves. Exercise 1.2. Draw an clause tree for the goal 'factorial(3,1,6)' having all true leaves, in a fashion similar to that done for factorial(3,6) previously. How do the two programs differ with regard to how they compute factorial? Also, trace the goal 'factorial(3,1,6)' using Prolog.

Q2.

Consider the following Tree.

/* Tree data and relations */ /* The tree database */ :- op(500,xfx,'is_parent'). a a a b b is_parent is_parent is_parent is_parent is_parent b. c. d. e. f. c c c d e is_parent is_parent is_parent is_parent is_parent */ g. h. i. j. k. f f h i i is_parent is_parent is_parent is_parent is_parent l. m. n. o. p. j j j m is_parent is_parent is_parent is_parent q. r. s. t.

/* X and

Y are siblings

:- op(500,xfx,'is_sibling_of'). X is_sibling_of Y :- Z is_parent X, Z is_parent Y, X \== Y. /* X and Y are on the same level in the tree. */ :-op(500,xfx,'is_same_level_as'). X is_same_level_as X is_same_level_as X . Y :- W is_parent X, Z is_parent Y, W is_same_level_as Z.

/* Depth of node in the tree. */ :- op(500,xfx,'has_depth'). a has_depth 0 :- !. Node has_depth D :- Mother is_parent Node, Mother has_depth D1, D is D1 + 1. /* Locate node by finding a path from root down to the node. */ locate(Node) :- path(Node), write(Node),

nl. path(a). path(Node) :- Mother is_parent Node, path(Mother), write(Mother), write(' --> '). /*

/* Can start at a. /* Choose parent, /* find path and then

*/ */ */

Calculate the height of a node, length of longest a leaf under the node. */

path to */

height(N,H) :- setof(Z,ht(N,Z),Set), max(Set,0,H). ht(Node,0) :- leaf(Node), !. ht(Node,H) :- Node is_parent Child, ht(Child,H1), H is H1 +1.

/* See section 2.8 for 'setof'.

leaf(Node) :- not(is_parent(Node,Child)). %/* Node grounded */ max([],M,M). max([X|R],M,A) :- (X > M -> max(R,X,A) ; max(R,M,A)).

The 'is_sibling_of' relationship tests whether two nodes have a common parent in the tree. For example,
?- h is_sibling_of S=g ; S=i ; no S.

Note the uses of the literal X \==Y, which succeeds just in case X and Y are not cobound (bound to the same value).The 'is_same_level_as' relationship tests whether two nodes are on the same level in the tree. The 'depth' predicate computes the depth of a node in the tree (how many edges from the root). For example,
?- t has_depth D. D=4

Here is an alternate definition of 'depth' using Prolog implication:


N has_depth D :- N == 'a' -> D=0 ; Mother is_parent N, Mother has_depth D1, D is D1 + 1.

The 'locate' predicate computes and prints a path from the root to a node. For example,
?- locate(n). a --> c --> h --> n

The 'leaf' predicate defines a leaf to be a node which is not a parent. Note the free variable inside the negation. This is correct, since if the node has any child then the node is not a leaf. The 'height' predicate computes the height of a node -- defined as the length of the longest path to a leaf under the node. This definition uses lists and the second-order Prolog predicate 'setof'. Exercise 2.1 Write a Prolog definition for 'ancestor(X,Y)' with the intended meaning that "X is an ancestor of Y in the tree". Pay attention: recursion from the top of the tree or from the bottom of the tree? Exercise 2.2 As written leaf/1 is intended as a test when Node is grounded. Reformulate leaf/1 so that the goal ?- leaf(X).will return values of X which are leaves in the tree. Exercise 2.3 Formulate definitions for a human family tree using relations 'male', 'female', 'parent', 'father', 'mother', 'sibling', 'grandparent', 'grandmother', 'grandfather', 'cousin', 'aunt', and 'uncle'. Let 'male', 'female', 'parent' be the fundamental relations and define the others in terms of these.

Q3.

DFA parser

The following program simulates a parser/acceptor for an arbitrary deterministic finite automaton (DFA). When this and a state table program are loaded into Prolog, the parser/acceptor may be used to check inputs to the DFA to see whether or not they are acceptable. The program traces its action using write statements; these have been indented in order to better display the logical structure of the clauses.
/* DFA parser */

parse(L) :- start(S), trans(S,L). trans(X,[A|B]) :delta(X,A,Y), write(X), write(' '), write([A|B]), nl, trans(Y,B). trans(X,[]) :final(X), write(X), write(' '), write([]), nl. /* X ---A---> Y */

delta(0,a,1). delta(0,b,0). delta(1,a,1). delta(1,b,2). delta(2,a,2). delta(2,b,2). start(0). final(2).

As an example, the following Prolog code specifies a state table for a DFA that accepts the language (a,b)*ab(a,b)* .
delta(0,a,1). delta(0,b,0). delta(1,a,1). delta(1,b,2). delta(2,a,2). delta(2,b,2). start(0). final(2).

A state diagram for this machine is as follows:

Suppose that both the driver program and the state table program are loaded ...
?- parse([b,b,a,a,b,a,b]). 0 [b,b,a,a,b,a,b] 0 [b,a,a,b,a,b] 0 [a,a,b,a,b] 1 [a,b,a,b] 1 [b,a,b] 2 [a,b] 2 [b] 2 [] yes ?0 0 0 no parse([b,b,a]). [b,b,a] [b,a] [a]

Exercise 3.1 Modify DFAParser so that it becomes a parser for NFAs, nondeterministic finite automata. Why is this extension such a natural one for Prolog? Exercise3.2 Using the DFA simulator presented here as motivation, design a Prolog simulator for Turing machines.

Вам также может понравиться