10. Logic Programming with Prolog
Total Page:16
File Type:pdf, Size:1020Kb
Copyright (C) R.A. van Engelen, FSU Department of Computer Science, 2000-2003 Logic Programming Logic programming is a form of declarative programming 10. Logic Programming With A program is a collection of axioms Each axiom is a Horn clause of the form: Prolog H :- B1, B2, ..., Bn. where H is the head term and B are the body terms Overview i Meaning H is true if all Bi are true Logic Programming A user of the program states a goal (a theorem) to be proven Prolog The logic programming system attempts to find axioms using inference steps that imply the goal (theorem) is true Note: Study Section 11.3 of the textbook, excluding 11.3.2. Resolution Prolog To deduce a goal (theorem), the logic programming system Uses backward chaining searches axioms and combines sub-goals More efficient than forward chaining for larger collections For example, given the axioms: of axioms C :- A, B. Interactive (hybrid compiled/interpreted) D :- C. Applications: expert systems, artificial intelligence, natural To deduce goal D given that A and B are true: language understanding, logical puzzles and games Forward chaining deduces that C is true: Popular system: SWI-Prolog C :- A, B Login: program.cs.fsu.edu and then that D is true: Type: pl to start SWI-Prolog D :- C Type: halt. to halt Prolog (note that a period is used as a Backward chaining finds that D can be proven if sub-goal C command terminator) is true: D :- C the system then deduces that the sub-goal is C is true: C :- A, B Since the system could prove C it has proven D Prolog Terms Prolog Clauses Terms are symbolic expressions that form the building blocks of A program consists of a database of Horn clauses Prolog Each clause consists of a head predicate and body predicates: A Prolog program consists of terms H :- B1, B2, ..., Bn. Data structures processed by a Prolog program are terms A clause is either a rule, e.g. A term is either snowy(X) :- rainy(X), cold(X). a variable: a name beginning with an upper case letter Meaning "If X is rainy and X is cold then this implies that X a constant: a number or string is snowy" an atom: a symbol or a name beginning with a lower case Or a clause is a fact, e.g. letter rainy(rochester). a structure of the form: Meaning "Rochester is rainy." functor(arg1, arg2, ..., argn) This fact is identical to the rule with true as the body where functor is an atom and argi are terms predicate: Examples: rainy(rochester) :- true. X, Y, ABC, and Alice are variables A predicate is a term (must be an atom or a structure) 7, 3.14, and "hello" are constants rainy(rochester) foo, bAR, and + are atoms member(X,Y) bin_tree(foo, bin_tree(bar, glarch)) and +(3,4) are true structures Queries and Goals Example Queries are used to "execute" goals Program with three facts and one rule: A query is interactively entered by a user after a program is rainy(seattle). loaded and stored in the database rainy(rochester). A query has the form cold(rochester). ?- G1, G2, ..., Gn. snowy(X) :- rainy(X), cold(X). Query and response: where Gi are goals A goal is a predicate to be proven true by the programming ?- snowy(rochester). system yes Example program with two facts: Query and response: rainy(seattle). ?- snowy(seattle). rainy(rochester). no Query with one goal to find which city C is rainy (if any): Query and response: ?- rainy(C). ?- snowy(paris). Response by the interpreter: no C = seattle Type a semicolon ; to get next solution: C = rochester Type another semicolon ;: no (no more solutions) Example (cont'd) Backtracking Program: For every successful match of a (sub-)goal with a head predicate rainy(seattle). of a clause, the system keeps this execution point in memory rainy(rochester). together with the current variable bindings to enable cold(rochester). backtracking snowy(X) :- rainy(X), cold(X). An unsuccessful match later forces backtracking in which ?- snowy(C). alternative clauses are searched that match (sub-)goals C = rochester Backtracking unwinds variable bindings to enable establishing because rainy(rochester) and cold(rochester) are sub-goals that new bindings are both true facts in the database snowy(X) with X=seattle is a goal that fails, because cold(X) fails, triggering backtracking Example: Family Relationships attire(mr_pope, watch). % If sir_raymond had tattered cuffs then mr_woodley had the Facts: pincenez: male(albert). attire(mr_woodley, pincenez) :- male(edward). attire(sir_raymond, tattered_cuffs). female(alice). female(victoria). % and vice versa: Rules: attire(sir_raymond,pincenez) :- parents(edward, victoria, albert). attire(mr_woodley, tattered_cuffs). parents(alice, victoria, albert). sister(X,Y) :- female(X), parents(X,M,F), parents(Y,M,F). % A person has tattered cuffs if he is in room 16: Query: attire(X, tattered_cuffs) :- room(X, 16). ?- sister(alice, X1). The system applies backward chaining to find the answer: % A person has black hair if he is in room 14, etc: 1. sister(alice, X1) matches 2nd rule: X = alice, Y = X1 hair(X, black) :- room(X, 14). 2. New goals: female(alice), parents(alice, M, F), hair(X, grey) :- room(X, 12). parents(X1, M, F) hair(X, brown) :- attire(X, pincenez). 3. female(alice) matches 3rd fact hair(X, red) :- attire(X, tattered_cuffs). 4. parents(alice, M, F) matches 2nd fule: M = victoria, F = albert % mr_holman was in room 12, etc: 5. parents(X1, victoria, albert) matches 1st rule: X1 = room(mr_holman, 12). edward room(sir_raymond, 10). room(mr_woodley, 16). Example: Murder Mystery room(X, 14) :- attire(X, watch). % the murderer had brown hair: murderer(X) :- hair(X, brown). % mr_holman had a ring: attire(mr_holman, ring). % mr_pope had a watch: Example: Murder Mystery (cont'd) Unification and Variables Question: who is the murderer? In the previous examples we saw the use of variables, e.g. C and ?- murderer(X). X Trace (indentation showing nesting depth): A variable is instantiated to a term as a result of unification murderer(X) Unification takes place when goals are matched to head hair(X, brown) predicates of rules and facts attire(X, pincenez) Goal in query: rainy(C) X = mr_woodley Fact in database: rainy(seattle) attire(sir_raymond, tattered_cuffs) Unification is the result of the goal-fact match: C = seattle room(sir_raymond, 16) Unification is recursive: FAIL (no facts or rules) An uninstantiated variable unifies with anything, even with FAIL (no alternative rules) other variables which makes them identical (aliases) REDO (found one alternative rule) An atom unifies with an identical atom attire(X, pincenez) A constant unifies with an identical constant X = sir_raymond A structure unfies with another structure if the functor and attire(mr_woodley, tattered_cuffs) number of arguments are the same and the corresponding room(mr_woodley, 16) arguments unify recursively SUCCESS Once a variable is instantiated to a non-variable term, it cannot SUCCESS: X = sir_raymond be changed and cannot be instantiated with a term that has a SUCCESS: X = sir_raymond different structure SUCCESS: X = sir_raymond SUCCESS: X = sir_raymond Unification Examples Lists The built-in predicate =(A,B) succeeds if and only if A and B A list is of the form: can be unified [elt1,elt2, ..., eltn] The goal =(A,B)may be written as A = B where elti are terms ?- a = a. The special list form yes [elt1,elt2, ..., eltn | tail] ?- a = 5. denotes a list whose tail list is tail no ?- [a,b,c] = [a|T]. ?- 5 = 5.0. T = [b,c] no ?- [a,b,c] = [a,b|T]. ?- a = X. T = [c] X = a ?- [a,b,c] = [a,b,c|T]. ?- foo(a,b) = foo(a,b). T = [] yes ?- foo(a,b) = foo(X,b). X = a ?- foo(X,b) = Y. Y = foo(X,b) ?- foo(Z,Z) = foo(a,b). no List Membership Predicates are Relations List membership is tested with the member predicate, defined Predicates are not functions with distinct inputs and outputs by Predicates are more general and define relationships between member(X, [X|T]). objects (terms) member(X, [H|T]) :- member(X, T). member(b, [a,b,c]) relates term b to the list that contains b ?- member(b, [a,b,c]). ?- member(X, [a,b,c]). Execution: X = a ; % type ';' to try to find more solutions member(b, [a,b,c]) does not match predicate member(X1, X = b ; % ... try to find more solutions X = c ; % ... try to find more solutions [X1|T1]) no member(b, [a,b,c]) matches predicate member(X , 1 ?- member(b, [a,Y,c]). [H1|T1]) Y = b with X1 = b, H1 = a, and T1 = [b,c] ?- member(b, L). Sub-goal to prove:member(X , T ) with X = b and T = L = [b|_G255] 1 1 1 1 therefore, L is a list with b as head and _G255 as tail, where [b,c] _G255 is a new variable member(b, [b,c]) matches predicate member(X , [X |T ]) 2 2 2 List appending predicate: with X2 = b and T2 = [c] append([], A, A). The sub-goal is proven, so member(b, [a,b,c]) is proven append([H|T], A, [H|L]) :- append(T, A, L). (deduced) ?- append([a,b,c], [d,e], X). Note: variables are "local" to a clause (just like the formal X = [a,b,c,d,e] arguments of a function) ?- append(Y, [d,e], [a,b,c,d,e]). Local variables such as X1 and X2 are used to indicate a Y = [a,b,c] match of a (sub)-goal and a head predicate of a clause ?- append([a,b,c], Z, [a,b,c,d,e]).