Prolog
Prolog
TECHNOLOGY
LAB MANUAL
DEPARTMENT OF
AIML
What is Prolog?
Prolog is a logic programming language that is used in artificial intelligence. It
is a declarative programming language expressing logic as relations, called facts
and rules. A Prolog program consists of a collection of facts and rules; a query is
a theorem to be proved. Here are some basic elements of Prolog:
Facts: These are statements that are true. They are written as a predicate
followed by a period. For example, `likes(john, mango).` is a fact that states that
John likes mango.
Rules: These are statements that define relationships between facts. They are
written as a predicate followed by a body, which is a list of one or more
predicates separated by commas and enclosed in parentheses, followed by a
period. For example,
Grandfather(X, Y) :-father(X,Z),parent(Z,Y)
This implies that for X to be the grandfather of Y, Z should be a parent of Y and
X should be the father of Z.
Queries: These are questions that we ask Prolog. They are written as a predicate
followed by a question mark. For example, `?- likes(john, mango).` is a query
that asks if John likes mango.
3. Handling Lists and Recursion: Prolog naturally handles lists and recursion,
making it well-suited for tasks that involve these concepts.
5. Backtracking: When a task fails, Prolog traces backward and tries to satisfy
the previous task. This backtracking feature allows for flexible problem-solving.
6. Efficiency: Prolog is known for its efficiency in solving problems that would
be difficult in other programming languages.
Symbols in Prolog
If --> :-
Not ~ Not
Or V ;
and ^ ,
Is understood as
P :- (Q,R);(S,T,U).
Or can also be written as:
P :- Q,R.
P :- S,T,U.
Example
happy(lili) :- dances(lili).
hungry(tom) :- search_for_food(tom).
friends(jack, bili) :- lovesCricket(jack), lovesCricket(bili).
goToPlay(ryan) :- isClosed(school), free(ryan).
Queries
Queries are some questions on the relationships between objects and object
properties. So question can be anything, as given below −
• Is tom a cat?
• Does Kunal love to eat pasta?
• Is Lili happy?
• Will Ryan go to play?
So according to these queries, Logic programming language can find the answer
and return them.
Knowledge Base in Logic Programming
In this section, we will see what knowledge base in logic programming is.
Well, as we know there are three main components in logic programming
− Facts, Rules and Queries. Among these three if we collect the facts and rules
as a whole then that forms a Knowledge Base. So we can say that the knowledge
base is a collection of facts and rules.
Now, we will see how to write some knowledge bases. Suppose we have our very
first knowledge base called KB1. Here in the KB1, we have some facts. The facts
are used to state things, that are unconditionally true of the domain of interest.
Knowledge Base 1
Suppose we have some knowledge, that Priya, Tiyasha, and Jaya are three girls,
among them, Priya can cook. Let’s try to write these facts in a more generic way
as shown below −
girl(priya).
girl(tiyasha).
girl(jaya).
can_cook(priya).
Note − Here we have written the name in lowercase letters, because in Prolog, a
string starting with uppercase letter indicates a variable.
Now we can use this knowledge base by posing some queries. “Is priya a girl?”,
it will reply “yes”, “is jamini a girl?” then it will answer “No”, because it does
not know who jamini is. Our next question is “Can Priya cook?”, it will say “yes”,
but if we ask the same question for Jaya, it will say “No”.
Output
GNU Prolog 1.4.5 (64 bits)
Compiled Jul 14 2018, 13:19:42 with x86_64-w64-mingw32-gcc
By Daniel Diaz
Copyright (C) 1999-2018 Daniel Diaz
| ?- change_directory('D:/TP Prolog/Sample_Codes').
yes
| ?- [kb1]
.
compiling D:/TP Prolog/Sample_Codes/kb1.pl for byte code...
D:/TP Prolog/Sample_Codes/kb1.pl compiled, 3 lines read - 489 bytes written,
10 ms
yes
| ?- girl(priya)
.
yes
| ?- girl(jamini).
no
| ?- can_cook(priya).
yes
| ?- can_cook(jaya).
no
| ?-
Let us see another knowledge base, where we have some rules. Rules contain
some information that are conditionally true about the domain of interest.
Suppose our knowledge base is as follows −
sing_a_song(ananya).
listens_to_music(rohit).
listens_to_music(ananya) :- sing_a_song(ananya).
happy(ananya) :- sing_a_song(ananya).
happy(rohit) :- listens_to_music(rohit).
playes_guitar(rohit) :- listens_to_music(rohit).
So there are some facts and rules given above. The first two are facts, but the rest
are rules. As we know that Ananya sings a song, this implies she also listens to
music. So if we ask “Does Ananya listen to music?”, the answer will be true.
Similarly, “is Rohit happy?”, this will also be true because he listens to music.
But if our question is “does Ananya play guitar?”, then according to the
knowledge base, it will say “No”. So these are some examples of queries based
on this Knowledge base.
Output
| ?- [kb2].
compiling D:/TP Prolog/Sample_Codes/kb2.pl for byte code...
D:/TP Prolog/Sample_Codes/kb2.pl compiled, 6 lines read - 1066 bytes written,
15 ms
yes
| ?- happy(rohit).
yes
| ?- sing_a_song(rohit).
no
| ?- sing_a_song(ananya).
yes
| ?- playes_guitar(rohit).
yes
| ?- playes_guitar(ananya).
no
| ?- listens_to_music(ananya).
yes
| ?-
Knowledge Base 3
The facts and rules of Knowledge Base 3 are as follows −
can_cook(priya).
can_cook(jaya).
can_cook(tiyasha).
likes(priya,jaya) :- can_cook(jaya).
likes(priya,tiyasha) :- can_cook(tiyasha).
Suppose we want to see the members who can cook, we can use one variable in
our query. The variables should start with uppercase letters. In the result, it will
show one by one. If we press enter, then it will come out, otherwise if we press
semicolon (;), then it will show the next result.
Let us see one practical demonstration output to understand how it works.
Output
| ?- [kb3].
compiling D:/TP Prolog/Sample_Codes/kb3.pl for byte code...
D:/TP Prolog/Sample_Codes/kb3.pl compiled, 5 lines read - 737 bytes written,
22 ms
warning: D:/TP Prolog/Sample_Codes/kb3.pl:1: redefining procedure
can_cook/1
D:/TP Prolog/Sample_Codes/kb1.pl:4: previous definition
yes
| ?- can_cook(X).
X = priya ? ;
X = jaya ? ;
X = tiyasha
yes
| ?- likes(priya,X).
X = jaya ? ;
X = tiyasha
yes
| ?-
yes
| ?- hates(X,tom).
X = jim ? ;
X = peter
yes
| ?- hates(_,tom).
true ? ;
no
| ?- hates(_,fox).
true ? ;
no
| ?-
Prolog Version
In this tutorial, we are using GNU Prolog, Version: 1.4.5
Official Website
This is the official GNU Prolog website where we can see all the necessary details
about GNU Prolog, and also get the download link.
http://www.gprolog.org/
Direct Download Link
Given below are the direct download links of GNU Prolog for Windows. For
other operating systems like Mac or Linux, you can get the download links by
visiting the official website (Link is given above) −
http://www.gprolog.org/setup-gprolog-1.4.5-mingw-x86.exe (32 Bit System)
http://www.gprolog.org/setup-gprolog-1.4.5-mingw-x64.exe(64 Bit System)
Installation Guide
• Download the exe file and run it.
• You will see the window as shown below, then click on next −
Select proper directory where you want to install the software, otherwise let it be
installed on the default directory. Then click on next.
You will get the below screen, simply go to next.
You can verify the below screen, and check/uncheck appropriate boxes,
otherwise you can leave it as default. Then click on next.
In the next step, you will see the below screen, then click on Install.
Now we can see in the prolog console, it shows that we have successfully changed
the directory.
Step 3 − Now create one file (extension is *.pl) and write the code as follows −
main :- write('This is sample Prolog program'),
write(' This program is written into hello_world.pl file').
Now let’s run the code. To run it, we have to write the file name as follows −
[hello_world]
The output is as follows −
In Prolog, the list builder uses brackets[...]. A list is referred by the notation [A |
B] in which, A is the first element, and whose tail is B. The following example
shows the three definitions, where the first element of the list is refereed by the
'car', the tail of the list is referred by 'cdr', list constructor is referred by the 'cons'.
1. car([A | B], A).
2. cdr([A | B], B).
3. cons[A, S, [A | S]).
Where,
However, the definitions of the above explicit are unneeded. The Prolog team
[A|B] refers that A is the head of list and B is its tail. A will bound to the first
element of the list, and B will bound to the tail of list if the list can be unified
with the team of prolog '[A|B]'.
In this section, many of the predicates are built-in for many interpreters of Prolog.
1. member(A, [A | S]).
2. member(A, [B | S]) :- member(A, S).
We can use this program in many ways. We can also test the membership as
follows:
1. ?- member(A, [1,2,3]).
2. A=1;
3. A=2;
4. A=3;
5. no
Here, the following derivation tree is used to show how all of the answers are
generated by this last goal.
Each left branch corresponds to a match against the first clause for 'member'. Each
right branch corresponds to a match against the second clause. On the lowest right
branch, the subgoal 'member(A, [])' will not match any 'member' clause head.
1. ?- member([3, B], [[1, a], [2, m], [3, z], [4, v], [3, p]]).
2. B=z;
3. B=p;
4. no
In the above query, we intend to search to find the elements which are paired with
a specified element. In a list, we can find elements in another way, and these
elements will satisfy some constraints:
1. ?- member(A, [23, 45, 67, 12, 222, 19, 9, 6]), B is A*A, B<100
2. A=9 B=81 ;
3. A=6 B=36 ;
4. no
1. member(A, [A | _]).
2. member(A, [_ | S]) :- member(A, S).
The "don't care" variable is shown by '_' (underscore). The "don't care" variable
is also known as an anonymous variable. In general, anonymous variables have
names in which underscore is the first character.
For example,
The above example explains that 'takeout(A, C, X)' can also be interpreted as
"insert A into X to produce C". We can also define:
Prolog - Backtracking
Let us see how backtracking takes place using one tree like structure −
Suppose A to G are some rules and facts. We start from A and want to reach G.
The proper path will be A-C-G, but at first, it will go from A to B, then B to D.
When it finds that D is not the destination, it backtracks to B, then go to E, and
backtracks again to B, as there is no other child of B, then it backtracks to A, thus
it searches for G, and finally found G in the path A-C-G. (Dashed lines are
indicating the backtracking.) So when it finds G, it stops.
Now, consider a situation, where two people X and Y can pay each other, but the
condition is that a boy can pay to a girl, so X will be a boy, and Y will be a girl.
So for these we have defined some facts and rules −
Knowledge Base
boy(tom).
boy(bob).
girl(alice).
girl(lili).
yes
| ?- pay(X,Y).
X = tom
Y = alice ?
X = tom
Y = alice ? ;
X = tom
Y = lili ? ;
X = bob
Y = alice ? ;
X = bob
Y = lili
yes
| ?- trace.
The debugger will first creep -- showing everything (trace)
X = tom
Y = alice ? ;
1 1 Redo: pay(tom,alice) ?
3 2 Redo: girl(alice) ?
3 2 Exit: girl(lili) ?
1 1 Exit: pay(tom,lili) ?
X = tom
Y = lili ? ;
1 1 Redo: pay(tom,lili) ?
2 2 Redo: boy(tom) ?
2 2 Exit: boy(bob) ?
3 2 Call: girl(_24) ?
3 2 Exit: girl(alice) ?
1 1 Exit: pay(bob,alice) ?
X = bob
Y = alice ? ;
1 1 Redo: pay(bob,alice) ?
3 2 Redo: girl(alice) ?
3 2 Exit: girl(lili) ?
1 1 Exit: pay(bob,lili) ?
X = bob
Y = lili
yes
{trace}
| ?-
Tree data structure of Prolog and case study :
Suppose we have a tree as shown below −
We have to implement this tree using prolog. We have some operations as follows
−
• op(500, xfx, ‘is_parent’).
• op(500, xfx, ‘is_sibling_of’).
• op(500, xfx, ‘is_at_same_level’).
• And another predicate namely leaf_node(Node)
In these operators, you have seen some parameters as (500, xfx,
<operator_name>). The first argument (here 500) is the priority of that operator.
The ‘xfx’ indicates that this is a binary operator and the <operator_name> is the
name of the operator.
These operators can be used to define the tree database. We can use these
operators as follows −
• a is_parent b, or is_parent(a, b). So this indicates that node a is the
parent of node b.
• X is_sibling_of Y or is_sibling_of(X,Y). This indicates that X is the
sibling of node Y. So the rule is, if another node Z is parent of X and
Z is also the parent of Y and X and Y are different, then X and Y are
siblings.
• leaf_node(Node). A node (Node) is said to be a leaf node when a
node has no children.
• X is_at_same_level Y, or is_at_same_level(X,Y). This will check
whether X and Y are at the same level or not. So the condition is
when X and Y are same, then it returns true, otherwise W is the
parent of X, Z is the parent of Y and W and Z are at the same level.
As shown above, other rules are defined in the code. So let us see the program to
get better view.
Program
/* The tree database */
:- op(500,xfx,'is_parent').
:- op(500,xfx,'is_sibling_of').
X is_sibling_of Y :- Z is_parent X,
Z is_parent Y,
X \== Y.
leaf_node(Node) :- \+ is_parent(Node,Child). % Node grounded
:-op(500,xfx,'is_at_same_level').
X is_at_same_level X .
X is_at_same_level Y :- W is_parent X,
Z is_parent Y,
W is_at_same_level Z.
Output
| ?- [case_tree].
compiling D:/TP Prolog/Sample_Codes/case_tree.pl for byte code...
D:/TP Prolog/Sample_Codes/case_tree.pl:20: warning: singleton variables
[Child] for leaf_node/1
D:/TP Prolog/Sample_Codes/case_tree.pl compiled, 28 lines read - 3244 bytes
written, 7 ms
yes
| ?- i is_parent p.
yes
| ?- i is_parent s.
no
| ?- is_parent(i,p).
yes
| ?- e is_sibling_of f.
true ?
yes
| ?- is_sibling_of(e,g).
no
| ?- leaf_node(v).
yes
| ?- leaf_node(a).
no
| ?- is_at_same_level(l,s).
true ?
yes
| ?- l is_at_same_level v.
no
| ?-
More on Tree Data Structure
Here, we will see some more operations that will be performed on the above given
tree data structure.
Let us consider the same tree here −
We will define other operations −
• path(Node)
• locate(Node)
As we have created the last database, we will create a new program that will hold
these operations, then consult the new file to use these operations on our pre-
existing program.
So let us see what is the purpose of these operators −
• path(Node) − This will display the path from the root node to the
given node. To solve this, suppose X is parent of Node, then find
path(X), then write X. When root node ‘a’ is reached, it will stop.
• locate(Node) − This will locate a node (Node) from the root of the
tree. In this case, we will call the path(Node) and write the Node.
Program
Let us see the program in execution −
path(a). /* Can start at a. */
path(Node) :- Mother is_parent Node, /* Choose parent, */
path(Mother), /* find path and then */
write(Mother),
write(' --> ').
yes
| ?- path(n).
a --> c --> h -->
true ?
yes
| ?- path(s).
a --> d --> j -->
true ?
yes
| ?- path(w).
no
| ?- locate(n).
a --> c --> h --> n
true ?
yes
| ?- locate(s).
a --> d --> j --> s
true ?
yes
| ?- locate(w).
no
| ?-