In the first section of this chapter we talked about facts and rules, relations, general sentences, and queries. Those words are all part of a discussion of logic and natural language. Now we're going to discuss the same ideas, but we're going to use more Prolog-ish words, like clauses, predicates, variables, and goals.
Basically, there are only two types of phrases that make up the Prolog language; a phrase can be either a fact or a rule. These phrases are known in Prolog as clauses. The heart of a Prolog program is made up of clauses.
More About Facts
A fact represents one single instance of either a property of an object or a relation between objects. A fact is self-standing; Prolog doesn't need to look any further for confirmation of the fact, and the fact can be used as a basis for inferences.
More About Rules
In Prolog, as in ordinary life, it is often possible to find out that something is true by inferring it from other facts. The Prolog construct that describes what you can infer from other information is a rule. A rule is a property or relation known to be true when some set of other relations is known. Syntactically, these relations are separated by commas, as we illustrate in example 1 below.
Examples of Rules
1. This first example shows a rule that can be used to conclude whether a menu item is suitable for Diane.
Diane is a vegetarian and eats only what her doctor tells her to eat.
Given a menu and the preceding rule, you can conclude if Diane can order a particular item on the menu. To do this, you must check to see if the item on the menu matches the constraints given.
a. Is Food_on_menu a vegetable?
b. Is Food_on_menu on the doctor's list?
c. Conclusion: If both answers are yes, Diane can order Food_on_menu.
In Prolog, a relationship like this must be represented by a rule because the conclusion is based on facts. Here's one way of writing the rule:
diane_can_eat(Food_on_menu):-
vegetable(Food_on_menu),
on_doctor_list(Food_on_menu).
Notice here the comma after vegetable(Food_on_menu). The comma introduces a conjunction of several goals, and is simply read as "and"; both vegetable(Food_on_menu) and on_doctor_list(Food_on_menu) must be true, for diane_can_eat(Food_on_menu) to be true.
Suppose you want to make a Prolog fact that is true if Person1 is the parent of Person2. This is easy enough; simply state the Prolog fact
parent(paul, samantha).
This shows that Paul is the parent of Samantha. But, suppose your Prolog database already has facts stating father relationships. For example, "Paul is the father of Samantha":
father(paul, samantha).
And you also have facts stating mother relationships; "Julie is the mother of Samantha":
mother(julie, samantha).
If you already had a collection of facts stating these father/mother relationships, it would be a waste of time to write parent facts into the database for each parent relationship.
Since you know that Person1 is the parent of Person2 if Person1 is the father of Person2 or if Person1 is the mother of Person2, then why not write a rule to convey these constraints? After stating these conditions in natural language, it should be fairly simple to code this into a Prolog rule by writing a rule that states the relationships.
parent(Person1, Person2):- father(Person1,
Person2).
parent(Person1, Person2):-
mother(Person1, Person2).
These Prolog rules simply state that
Person1 is the parent of Person2 if Person1 is the father of Person2.
Person1 is the parent of Person2 if Person1 is the mother of Person2.
3. Here's another example:
A person can buy a car if the person likes the car and the car is for sale.
This natural language relationship can be conveyed in Prolog with the following rule:
can_buy(Name, Model):-
person(Name),
car(Model),
likes(Name,
Model),
for_sale(Model).
This rule shows the following relationship:
Name can_buy Model if
Name is a person
and
Model is a car and
Name likes Model
and
Model is for
sale.
This Prolog rule will succeed if all four conditions in the body of the rule succeed.
4. Here is a program designed to find solutions to this car-buying problem:
/* Program ch02e02.pro */
PREDICATES /* clauses ¼½¼Ç¿¡¼ »ç¿ëµÉ predicate ¼±¾ð */
nondeterm can_buy(symbol, symbol)
nondeterm person(symbol)
nondeterm
car(symbol)
likes(symbol,
symbol)
for_sale(symbol)
CLAUSES /* fact (°´Ã¼¿Í ±×µéÀÇ °ü°è) ¿Í rule ·Î ±¸¼º */
can_buy(X,Y):- /* rule ÀÇ °á·ÐºÎ */
person(X), /* rule ÀÇ Á¶°ÇºÎ */
car(Y), /* Á¶°ÇºÎ´Â Çϳª ÀÌ»óÀÇ AND³ª OR·Î ¿¬°áµÈ ºÎ¸ñÇ¥¸¦ °¡Áü */
likes(X,Y), /* prolog¿¡¼ , ´Â AND À̰í ; ´Â OR ÀÌ´Ù */
for_sale(Y).
person(kelly).
person(judy).
person(ellen).
person(mark).
car(lemon).
car(hot_rod).
likes(kelly,
hot_rod).
likes(judy, pizza).
likes(ellen,
tennis).
likes(mark, tennis).
for_sale(pizza).
for_sale(lemon).
for_sale(hot_rod).
GOAL /* prolog ¿¡ ´ëÇÑ Áú¹® (query) */
can_buy(Who,What). /* ±â¾ïµÈ fact ¿Í Áú¹®ÀÌ ÀÏÄ¡ÇÑ ³»¿ëÀÌ ÀÖ´ÂÁö °Ë»ö */
/* prolog¿¡¼ goalÀ» Á¦°øÇÏ´Â ¹æ¹ýÀº program ¿¡ Goal ¼½¼ÇÀ» µÎ´Â ¹æ¹ý°ú program ½ÇÇà½Ã ÇÊ¿äÇÑ ¸ñÇ¥¸¦ dialog window¿¡ Á¦°øÇÏ´Â ¹æ¹ýÀÌ ÀÖ´Ù */
Ãâ·Â
Who=kelly, What=hot_rod
1 solution
What can Judy and Kelly buy? Who can buy the hot rod? You can try the following goals:
can_buy(Who, What).
can_buy(judy, What).
can_buy(kelly, What).
can_buy(Who, hot_rod).
Experiment! Add other facts and maybe even a rule or two to this Prolog program. Test the new program with queries that you make up. Does Prolog respond in a way you would expect it to?
Exercises
Write natural-language sentences corresponding to the following Visual Prolog rules:
eats(Who, What):- food(What), likes(Who, What).
pass_class(Who):- did_homework(Who), good_attendance(Who).
does_not_eat(toby, Stuff):- food(Stuff), greasy(Stuff).
owns(Who, What):- bought(Who, What).
Write Visual Prolog rules that convey the meaning of these natural-language sentences:
a. A person is hungry if that person's stomach is empty.
b. Everybody likes a job if it's fun and it pays well.
c. Sally likes french fries if they're cooked.
d. Everybody owns a car who buys one, pays for it, and keeps it.
The symbolic name of a relation is called the predicate name. The objects that it relates are called its arguments; in the fact likes(bill, cindy)., the relation likes is the predicate and the objects bill and cindy are the arguments.
Here are some examples of Prolog predicates with zero or more arguments:
pred(integer, symbol)
person(last, first, gender)
run
insert_mode
birthday(firstName, lastName, date)
As we've shown here, a predicate might not have any arguments at all, but the use of such a predicate is limited. You can use a query such as person(rosemont,Name,male). to find out Mr. Rosemont's first name. But what can you do with the zero-argument query run? You can find out whether the clause run is in the program, or--if run is the head of a rule, you can evaluate that rule. This can be useful in a few cases--for instance, you might want to make a program behave differently depending on whether the clause insert_mode. is present.
In a simple query, you can use variables to ask Prolog to find who likes tennis. For example:
likes(X, tennis).
This query uses the letter X as a variable to indicate an unknown person. Variable names in Visual Prolog must begin with a capital letter (or an underscore), after which any number of letters (upper-case or lower-case), digits, or underline characters (_) can be used. For example, the following are valid variable names:
My_first_correct_variable_name
Sales_10_11_86
while the next three are invalid:
1stattempt
second_attempt
"disaster"
(Careful choice of variable names makes programs more readable. For example,
likes(Person, tennis).
is better than
likes(X, tennis).
because Person makes more sense than X.) Now try the goal
GOAL likes(Person, tennis).
Visual Prolog replies
Person=ellen
Person=mark
2 Solutions
because the goal can be solved in just two ways; namely, by taking the variable Person and successively matching it with the values ellen and mark.
In variable names, except for the first character (which must be an upper-case letter or an underscore), Visual Prolog allows lower-case or upper-case letters in any position. One way to make variable names more readable is by using mixed upper-case and lower-case letters, as in
IncomeAndExpenditureAccou
º¯¼ö°¡ °ªÀ» ¾ò´Â ¹æ¹ý
Take a look at the following example, which uses program 3 to demonstrate how and when variables get their values.
/* Program ch02e03.pro */
PREDICATES
nondeterm likes(symbol,symbol)
CLAUSES
likes(ellen,reading).
likes(john,computers).
likes(john,badminton).
likes(leonard,badminton).
likes(eric,swimming).
likes(eric,reading).
GOAL
likes(Person, reading),
likes(Person, swimming).
/* óÀ½¿¡ query ÀÇ Ã³À½ part¿¡ ´ëÇØ top down ¹æÇâÀ¸·Î clauses¸¦ Ž»ö »çÀÛ-> º¯¼ö PersonÀº free»óÅ (free variable, ÀÚÀ¯º¯¼ö) -> µÎ¹øÂ° Àμö reading °ú match µÇ´Â fact¸¦ ¹ß°ß -> Person Àº ellen À¸·Î bind µÇ°í (bound variable, ÇÑÁ¤º¯¼ö) µ¿½Ã¿¡ fact list »ó¿¡ pointer¸¦ À§Ä¡½ÃÅ´ -> query ÀÇ µÎ¹øÂ° part ¼öÇà, Áï likes(ellen, swimming)À» óÀ½ºÎÅÍ Ã£´Â´Ù, Person is ellen¿¡ ´ëÇØ not true -> Person Àº unbind µÇ°í ´Ù½Ã free, query ÀÇ Ã³À½ part¿¡ ´ëÇØ ´Ù¸¥ solutionÀ» ã´Â´Ù -> ¶Ç´Ù¸¥ fact¸¦ ã±âÀ§ÇØ pointer À§Ä¡·Î ´Ù½Ã µ¹¾Æ°£´Ù, À̰ÍÀ» backtracking À̶ó ÇÑ´Ù -> Person Àº ´Ù½Ã ericÀ¸·Î bound µÇ°í µÎ¹øÂ° part¿¡¼ likes(eric,swimming) ¶ó´Â fact¸¦ ¹ß°ßÇÏ¿© matching -> query°¡ ¸¸Á·µÇ¾î °á°ú¸¦ ¸®ÅÏ */
Ãâ·Â
Person=eric
1 solution
Anonymous Variables
query¿¡¼ ¾î¶² Á¤º¸¸¦ ÇÊ¿ä·Î ÇÏÁö¸¸ ¾î¶² °ªÀ» °¡ÁöµçÁö »ó°ü¾ø´Ù¸é Anonymous Varialbles¸¦ »ç¿ëÇÒ ¼ö ÀÖ´Ù. Anonymous Varialbles ´Â underscore ("_") ·Î¼ Ç¥ÇöµÈ´Ù. Anonymous Variables´Â ¾î¶² º¯¼ö ´ë½Å¿¡µµ »ç¿ëÇÒ ¼ö´Â ÀÖÁö¸¸ °áÄÚ °ªÀ» °¡Áú ¼ö´Â ¾ø´Ù. ¾î¶² »ç¶÷µéÀÌ parents ÀÎÁö¸¦ ¾Ë·Á°í ÇÑ´Ù¸é ±×µéÀÇ ÀÚ½ÄÀÌ ´©±¸ÀÎÁö¸¦ ¾Ë ÇÊ¿ä´Â ¾ø´Ù. À̶§¿¡ underscore¸¦ »ç¿ëÇÏ¿© º¯¼ö °ø°£ÀÇ °ªÀ» ¹«½ÃÇÑ´Ù. Áï ´ë°³ »ç¿ëÀÚ°¡ °ü½ÉÀ» °®Áö ¾Ê´Â ´ë»óÀÇ º¯¼ö´Â underlineÀ» »ç¿ëÇÏ¿© º¯¼ö ´ë½Å »ç¿ëÇÑ´Ù
/* Program ch02e04.pro */
PREDICATES
male(symbol)
female(symbol)
nondeterm parent(symbol,
symbol)
CLAUSES
male(bill).
male(joe).
female(sue).
female(tammy).
parent(bill,joe).
parent(sue,joe).
parent(joe,tammy).
GOAL
parent(Parent, _).
Ãâ·Â
Parent=bill
Parent=sue
Parent=joe
3 solutions
In this case, because of the anonymous variable, Prolog finds and reports three parents, but it does not report the values associated with the second argument in the parent clause.
Anonymous variables can also be used in facts. The following Prolog facts
owns(_, shoes).
eats(_).
could be used to express the natural language statements
Everyone owns shoes.
Everyone eats.
The anonymous variable matches anything. A named variable would work equally well in most cases, but its name would serve no useful purpose.
Up to now, we've been mixing the word query when talking about the questions you ask Prolog, with the more common name goal, which we'll use from now on. Referring to queries as goals should make sense: when you query Prolog, you are actually giving it a goal to accomplish ("Find an answer to this question, if one exists: ...").
Goals can be simple, such as these two:
likes(ellen, swimming).
likes(bill, What).
or they can be more complex. In the "Variables" section of this chapter, you saw a goal made up of two parts:
likes(Person, reading), likes(Person, swimming).
A goal made up of two or more parts is known as a compound goal, and each part of the compound goal is called a subgoal.
Often you need to know the intersection of two goals. For instance, in the previous parents example, you might also need to know which persons are male parents. You can get Prolog to search for the solutions to such a query by setting a compound goal. Load the Program 4 and enter the following compound goal:
Goal parent(Person, _), male(Person).
Prolog will first try to solve the subgoal
parent(Person, _)
by searching the clauses for a match, then binding the variable Person to a value returned by parent (Person is a parent). The value that parent returns will then provide the second subgoal with the value on which to search (Is Person--now bound--a male?).
male(Person)
If you entered the goal correctly, Prolog will answer
Person=bill
Person=joe
2 Solutions
Compound Goals: Conjunctions and Disjunctions
º¹ÇÕ ¸ñÇ¥ Áï subgoal A and subgoal B (=conjunction, and)À» Ç¥ÇöÇϱâÀ§ÇØ comma (,)¸¦ »ç¿ëÇϰųª subgoal A or subgoal B (=disjunction, or)À» Ç¥ÇöÇϱâÀ§ÇØ semicolon(;)À» »ç¿ëÇÑ´Ù
PREDICATES
car(symbol,long,integer,symbol,long)
truck(symbol,long,integer,symbol,long)
nondeterm vehicle(symbol,long,integer,symbol,long)
CLAUSES
car(chrysler,130000,3,red,12000).
car(ford,90000,4,gray,25000).
car(datsun,8000,1,red,30000).
truck(ford,80000,6,blue,8000).
truck(datsun,50000,5,orange,20000).
truck(toyota,25000,2,black,25000).
vehicle(Make,Odometer,Age,Color,Price):-
car(Make,Odometer,Age,Color,Price);
truck(Make,Odometer,Age,Color,Price).
GOAL
car(Make,
Odometer, Years_on_road, Body, 25000).
/* °ªÀÌ Á¤È®ÇÏ°Ô 25000 ÀÎ Â÷¸¦ ã¾Æ³½´Ù. Á»´õ ÀÚ¿¬½º·´°Ô 25000 ºÒ ÀÌÇÏÀÇ Â÷¸¦ ã¾Æ³»·Á¸é car(Make, Odometer, Years_on_road, Body, Cost), Cost < 25000. °ú °°ÀÌ subgoal A and subgoal B ·Î Ç¥ÇöÇØ¾ß ÇÑ´Ù. $25,000 ÀÌÇÏÀÇ car À̰ųª $20,000 ÀÌÇÏÀÇ truckÀº ? ¸¦ Ç¥ÇöÇÏ·Á¸écar(Make,Odometer,Years_on_road,Body,Cost), Cost<25000 ; truck(Make,Odometer,Years_on_road,Body,Cost), Cost < 20000. ¿Í °°ÀÌ subgoal A or subgoal B ·Î Ç¥ÇöÇØ¾ß ÇÑ´Ù. */
Ãâ·Â
Make=ford, Odometer=90000, Years_on_road=4, Body=gray
1 solution
But this goal is slightly unnatural, since you'd probably rather ask a question like:
Is there a car listed that costs less than $25,000?
You can get Visual Prolog to search for a solution by setting this compound goal:
car(Make, Odometer, Years_on_road, Body, Cost),
/*subgoal A and*/
Cost < 25000. /*subgoal
B */
This is known as a conjunction. To fulfill this compound goal, Prolog will try to solve the subgoals in order. First, it will try to solve
car(Make, Odometer, Years_on_road, Body, Cost).
and then
Cost < 25000.
with the variable Cost referring to the same value in both subgoals. Try it out now.
Note: The subgoal Cost < 25000 involves the relation less than, which is built into the Visual Prolog system. The less than relation is no different from any other relation involving two numeric objects, but it is more natural to place the symbol for it between the two objects.
Now we will try to see if the following, expressed in natural language, is true:goals, disjunctivedisjunctive goals queries, disjunctive
Is there a car listed that costs less than $25,000?, or is there a truck listed that costs less than $20,000?
Prolog will search for a solution if you set this compound goal:
car(Make,Odometer,Years_on_road,Body,Cost),
Cost<25000 ;
/*
subgoal A or */
truck(Make,Odometer,Years_on_road,Body,Cost),
Cost < 20000.
/*
subgoal B */
This kind of compound goal is known as a disjunction. This one sets up the two subgoals as alternatives, much as though they were two clauses for the same rule. Prolog will then find any solution that satisfies either of the subgoals.
To fulfill this compound goal, Prolog will try to solve the first subgoal ("find a car ..."), which is composed of these subgoals:
car(Make, Odometer, Years_on_road, Body, Cost.)
and
Cost < 25000.
If a car is found, the goal will succeed; if not, Prolog will try to fulfill the second compound goal ("find a truck ..."), made up of the subgoals
truck(Make, Odometer, Years_on_road, Body, Cost),
and
Cost < 20000.
It's good programming style to include comments in your program to explain things that might not be obvious to someone else (or to you in six months). This makes the program easy for you and others to understand. If you choose appropriate names for variables, predicates, and domains, you'll need fewer comments, since the program will be more self-explanatory.
Multiple-line comments must begin with the characters /* (slash, asterisk) and end with the characters */ (asterisk, slash). To set off single-line comments, you can use these same characters, or you can begin the comment with a percent sign (%).
/* This is an example of a comment */
% This is also a comment
/***************************************/
/* and so are these three lines */
/***************************************/
/*You can also nest a Visual
Prolog comment /*within a
comment*/ like this */
In Visual Prolog 5.0 you can also use a comment after de decalratition of a domain.
DOMAINS
articles = book(STRING title, STRING author); horse(STRING name)
PREDICATES
conv(STRING uppercase,STRING lowercase)
The words title, author, name, uppercase and lowercase will be ignored by the compiler, but makes the program much more readable.