Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.
More About Rules and Goals CS321 Spring 2008
More complicated goals • So far, we have used simple goal statements. • As with rule clauses, goals can be made compound by using • conjunction … "and" • disjunction … "or"
Example prog4 • See buy_car file • As written, looks for a car that costs less than or equal to $25,000. buy_car(Model,Color):- car(Model,Color,Price), colors(Color,jazzy), Price =< 25000. car(maserati,green,25000). car(corvette,black,24000). car(corvette,red,25000). car(porsche,red,24000). colors(red,jazzy). colors(black,jazzy). colors(green,preppy).
Revision • How can we search for a solution to the question: • Is there a car listed that costs less than $25,000, or is there a truck that costs less than $20,000 ?
Revision • Is there a car listed that costs less than $25,000, or is there a truck that costs less than $20,000 ? car(Make,Odometer,Years_on_road, Body,Cost), Cost<25000; truck(Make,Odometer,Years_on_road, Body,Cost), Cost < 20000. conjunction disjunction Note that conjunction has precedence over disjunction
Order of Pattern Matching • In a compound goal, Prolog first checks to see if it can find a match for the first subgoal, then the next subgoal, etc. • if the goal is a conjunction, all subgoals must be successful • in a disjunction, the first subgoal that succeeds is reported. • Then, Prolog backtracks to try other possible solutions, including other subgoals
Matching in Compound Goals • As with rules: • if the same free variable occurs in multiple sub-goals of the same goal, • the first match binds and then other instances of the same variable must have the same binding • Example: parent(bill,X), parent(X,tammy) must have same binding
Matching in Compound Goals File Prog3-1.pro male(bill). male(joe). female(sue). female(tammy). parent(bill,joe). parent(sue,joe). parent(joe,tammy). parent(bill,X), parent(X,tammy). X = joe ? ; no | ? - The first goal is resolved with X bound to “joe” When the second goal is resolved X is already bound to “joe”. Prolog is just testing if “parent(joe,tammy)” is a fact.
Pointers • Two free variables can match each other. • For example, if parent(joe,X) in a rulematches parent(joe,Y) in a goal the variables X and Y are bound to each other. • As long as the binding lasts, X and Y are treated as a single variable, and if one of them gets a value the other one will immediately have the same value. • When free variables are bound to each other like this, they're called pointers.
Including other files • The include directive has the same effect as the #include in C. • Syntax: • At the top of the file add: :- include('fileName.pro'). • The colon dash at the beginning of a line indicates that the line is a directive, not a predicate. • Note that the single quotes are essential.
Adding Facts • Two steps to adding a fact to a clause while in the interpreter • You must first make the clause dynamic in the original file • E.g., :- dynamic(direct_route/2) The /2 indicates that direct_route takes two parameters. The :- means “compiler directive”. Will not work without this!
Adding Facts • Two steps to adding a fact to a clause while in the interpreter • You can then use asserta(direct_route(nyc, chicago) directive • Or can use the assertz(direct_route(nyc, chicago) directive Adds the rule to the beginning of the database Adds the rule to the end of the database
Example • See travel.pro for an example of the include and dynamic directives. % the following line includes the file teaches.pro into this file :- include('teaches.pro'). % the following line makes the predicate direct_route dynamic, % i.e., you can add new facts while in the interpreter. % the /2 means that direct_route requires two parameters. :- dynamic(direct_route/2). direct_route(ithaca, syracuse). direct_route(syracuse, orlando). direct_route(ithaca, nyc). direct_route(syracuse, nyc). direct_route(syracuse, sanfrancisco). direct_route(syracuse, boston). travel(A,B) :- direct_route(A, B). travel(A,B) :- direct_route(A, C), travel(C,B).
Recursion • In a Prolog program, a rule is said to be recursive if the predicate symbol of its head reoccurs in its body as a predicate symbol. • For example, to say that X is a citizen of Southland if X is a child of a Southland-citizen, we could write: southlander(X) :- child(X,Y), southlander(Y).
Requirements for Recursion • To write recursive rules, be sure to provide two rules • At least one trivial rule that is not recursive • The recursive rule • May be written in either order • But better to put the stopping condition first • This ensures Prolog will evaluate the nonrecursive rule before recursing. • Also better to use tail recursion • Put the recursive predicate at the end of the rule.
recursion • a recursive program: % 1 terminating condition sum_ints(X, 0) :- X is 0. % 2 recursive sum_ints(X, Count) :- Count > 0, N is Count - 1, sum_ints(Y, N), X is Y + Count. This is not tail recursion! Note that the clause: Count is Count - 1, will always fail!
Example travel(A,B) :- direct_route(A, B). travel(A,B) :- direct_route(A, C), travel(C,B). • This codes a problem of traveling between cities where traveling from A to B is possible if there is a direct route from A to B or if there is a direct route from A to C and traveling from C to B is possible. • Is this code “tail recursion” or is it “constructive recursion”? • See next slide.
Example • Travel.pro direct_route(ithaca, syracuse). direct_route(syracuse, orlando). direct_route(ithaca, nyc). direct_route(syracuse, nyc). direct_route(syracuse, sanfrancisco). direct_route(syracuse, boston). travel(A,B) :- direct_route(A, B). travel(A,B) :- direct_route(A, C), travel(C,B). This is tail recursion!
Example (cont) • What if we add the fact: direct_route(syracuse, ithaca). • When we try travel(ithaca, varna). Get infinite recursion (until the stack overflows). • Why? • Can we fix this? Not yet, need predicate that we’ll learn later (cut)
Example 2 drains_to(X, Y) :- tributary(X, Y). drains_to(X, Z) :- tributary(X, Y), drains_to(Y, Z). tributary(mississippi, gulf_of_mexico). tributary(missouri, mississippi). tributary(ohio, mississippi). tributary(kanawha, ohio). tributary(hurricane_ck, kanawha). tributary(poplar_fork_ck, hurricane_ck). tributary(eighteen_mile_ck, kanawha). tributary(long_branch, poplar_fork_ck). tributary(jakes_branch, eighteen_mile_ck). tributary(sandusky, lake_erie).
Example 2 • What happens if you write the rule as: drains_to(X, Y) :- tributary(X, Y). drains_to(X, Z) :- drains_to(Y, Z), tributary(X, Y). Get correct answers but also infinite recursion! Reason: both variables in the drains_to predicate are unsubstantiated, so Prolog continues to match them over and over.
Tail recursion • Changing a recursive program into tail recursion: sum_ints(X, Count) :- sum_help(X,0, Count). % 1 terminating condition sum_help(X, Temp, 0) :- X is Temp. % 2 recursive sum_help(X, Temp, Count). Count > 0, N is Count - 1, Y is Temp + Count, sum_help(X, Y, N). This is tail recursion! X is not calculated on the way up the recursion tree; it is bound in the halting case. Why do we use the variable ‘Y’?
Computation • Logic programming can be applied to conventional computational kinds of tasks. • As with functional languages, the solution to a computation is often recursive.
Prolog pattern matches variables. This is not a function call, N-1 is not a parameter! Computation is not performed during unification! Factorial: first try badFact(0):- 1. badFact(N, F) :- N > 0, N * badFact(N-1,F). Why doesn't this work?
Example: fact1-2.pro factorial(0, 1). factorial(N, F) :- N > 0, N1 is N-1, factorial(N1,F1), F is N*F1. Goal: factorial(4, What). Illegal goal: factorial(What, 720). % N must be instantiated to do N > 0 The assignment operator for arithmetic in GNU prolog is the word ‘is’ These rules can go in either order. Why use F1 instead of F? Computation is not performed during unification. Therefore, we do not write factorial(N-1, F1).
Halting conditions • Note the halting condition was factorial(1,0). • Not factorial(1) :- 1. • The first predicate is a fact. • If you say factorial(1,X). This rule can be matched. • The second predicate is a rule that means nothing • The rule reads factorial of 1 matches 1. Will not compile! • Note that rules are not procedures!
Error Checking • In the recursive factorial rule the first predicate is: N > 0, • Do this to ensure that we don’t try to backtrack and unify with N less than 0.
Negation • The use of negation in Prolog programs is best described using an example. • Try Prolog example 5 (Prog5-2.pro) with each of the following goals: • bachelor(henry). • bachelor(tom). • bachelor(Who). • \+(married(tom)). The symbol for not in GNU prolog is‘\+’
Negation • Negation is actually failure. • Prolog tries to make the goal succeed. • If it can't, the the failure is true.