Prolog-machine consists of two components:
the program (Horn clauses and directives) is entered into the database. then interpreter loads this DB and starts REPL
the task of the programmer is simply to describe problems
the programmer should write down a declarative specification which describes the situation of interest. the programmer shouldn't have to tell the computer what to do. to get information, s/he simply asks the questions - it's up to the logic programming system to figure out how to get the answer
any string starting with %
is a comment. there are no multiline comments in Prolog
in PROLOG two types of constants are distinguished:
an atom is either:
name, big_ban, m_2
are atoms
'Arthur', 'The Lord', 'Five_Dollar_Shake', ' '
are atoms
@= ====> ; :-
are all atoms
a variable is a string of upper-case letters, lower-case letters, digits and underscore characters that starts either with an upper-case letter or with underscore. X, Var, Y_24, List2, _head
are all PROLOG variables
the variable _
(that is, a single underscore character) is called the anonymous variable
a variable has for its lexical scope the clause in which it occurs - outside that clause, the variable has no influence: PROLOG does NOT have global variables
functor in Prolog is construction p(t1, t2, ..., tn)
where
the functor is defined by name (predicate) and arity (number of terms)
the terms of functor are called arguments. the arguments of a functor are enclosed in parentheses, and separated by commas. they can be
tuple's matching:
| ?- (_,_,_,X) = ([a, b], [1, 2], [c], d). X = d yes
Horn clause p :- p1, p2, ..., pn.
is interpreted as "p is true if p1 AND p2 AND ... AND pn are true"
Horn clause p :- p1; p2; ...; pn.
is interpreted as "p is true if p1 OR p2 OR ... OR pn are true"
p
is called conclusion
if a clause contains conditions (that is in clause n ≠ 0), it is called a rule
if there are no conditions (that is in clause n = 0), the clause is said to be a fact
in this case functor is used: p(p1,p2,...,pn).
if the conclusion p
is missing then the clause is considered to be a query. in this case the atom :-
is replaced by the atom ?-
set of such clauses is viewed as a entire program
interpreter tries to derive an answer to the query using facts and rules stored in the database. doing so interpreter employs two techniques: matching and backtracking
rules extend the capabilities of a logic program. they are what give Prolog the ability to pursue its decision-making process. the following program contains two rules for temperature:
'it is sunny'. 'it is summer'. 'it is hot' :- 'it is summer', 'it is sunny'. 'it is cold' :- 'it is winter'; 'it is snowing'.
?- 'it is hot'. yes
?- 'it is cold'. no
listing multiple rules with the same head is a way of expressing logical disjunction (that is, it is a way of saying OR)
fact1(a) :- true . fact2(b) :- true . rule01(X) :- fact1 . rule01(X) :- fact2 .
there is another way of expressing disjunction. you could replace the pair of rules by the single rule
fact1(a) :- true . fact2(b) :- true . rule01(X) :- fact1 ; fact2 .
to answer a query, the interpreter starts with the first condition in the query clause, taking it as a procedure call. the database is subsequently searched for a suitable entry to the called procedure
the search starts with the first clause in the database, and continues until a clause has been found which has a conclusion that can be matched with the procedure call
a match is obtained, if there exists a substitution for the variables occurring both in the conclusion and in the procedure call, such that the two become (syntactically) equal after the substitution has been applied to them
such a match exists if
if, after the creation of a number of instantiations and matches, the system does not succeed in obtaining the next match, it systematically tries alternatives for the instantiations and matches arrived at so far
interpreter examines clauses in the order in which they have been specifed in the database. the order in which clauses have been specifed in the database may be important. this is a substantial diference between a logic program and a PROLOG program: whereas logic programs are purely declarative in nature, PROLOG programs tend to be much more procedural
u can cut backtracking by using !
. basically, it tells Prolog not to backtrack and stop to look for alternative solutions for the goal
max(A,B,B) :- A < B, !. max(A,B,A).
the only method that Prolog can use to tell if a proposition is false is to try to prove it (from the facts and rules that it has been told about), and then if this attempt fails, it concludes that the proposition is false. an obvious problem is that Prolog may not have been told some critical fact or rule, so that it will not be able to prove the proposition. this is sometimes referred to as the closed-world assumption. a less obvious problem is that it may take a very long time to determine that the proposition cannot be proven. in certain cases - infinite time
negation in Prolog is represented using the symbol \+
, which is supposed to be a mnemonic for not provable with the \ standing for not and the + for provable
?- \+ (2 = 4). yes.
you start REPL just by:
$> gprolog GNU Prolog 1.4.5 (64 bits) Compiled Jul 14 2018, 13:34:14 with gcc By Daniel Diaz Copyright (C) 1999-2019 Daniel Diaz | ?-
the next two in-build predicates tell PROLOG to consult the file "kb.pl", and load the contents as its new knowledge base. you can use
| ?- [kb]. compiling /home/Prolog/kb.pl for byte code... /home/../kb.pl compiled, 7 lines read - 586 bytes written, 15 ms yes
| ?- consult('kb.pl'). compiling /home/Prolog/kb.pl for byte code... /home/../kb.pl compiled, 7 lines read - 586 bytes written, 15 ms yes
| ?- listing. % file: /home/../kb.pl man(noi). man(kain). man(abel). father(noi, kain). father(noi, abel). yes
a yes means that the information in the data base is consistent with the subject of the query. another way to express this is that the program is capable of proving the query true with the available information in the data base. if a fact is not deducible from the data base the system replys with a no, which indicates that based on the information available (the closed world assumption) the fact is not deducible
to exit from REPL use in-built Prolog predicate halt:
| ?- halt. $>
using Ctrl-C u get additional menu for REPL
%%% file kb.pl man(noi). man(kain). man(abel). father(noi, kain). father(noi, abel).
$> gProlog --consult-file kb.pl GNU Prolog 1.4.4 (32 bits)... | ?- man(X). X = noi ? ; X = kain ? ; X = abel yes | ?- father(X,abel). X = noi yes | ?- father(noi,X). X = kain ? ; X = abel yes | ?-
when you write a recursive predicate, it should always have at least two clauses:
recursive rules are really important. they enable to pack an enormous amount of information into a compact form and to define predicates in a natural way. most of the work you will do as a Prolog programmer will involve writing recursive rules
numeral(0). numeral(succ(X)) :- numeral(X). add(0, Y, Y). add(succ(X), Y, succ(Z)) :- add(X, Y, Z).
there is a special notation for lists in PROLOG: [ ]
. lists in Prolog are geterogenious
| ?- X = [alfa, beta, 5, Y, [gamma, 12], man(iosif)]. yes
a in-built operator |
which can be used to decompose a list into its head and tail
| ?- [Head | Tail] = [alfa, beta, delta, gamma]. Head = alfa Tail = [beta,delta,gamma] yes
a in-built predicate
length/2
| ?- X = [1,2,3,4], length(X,N). N = 4 X = [1,2,3,4] yes
a in-built predicate member/2
| ?- member(X, [alfa, beta, delta, gamma]). X = alfa; X = beta; X = delta; X = gamma; yes
a in-built predicate append/3
| ?- X = [1,2,3], append(X,[25,26],Y), write(Y). [1,2,3,25,26] X = [1,2,3] Y = [1,2,3,25,26] yes
a in-built predicate reverse/2
| ?- reverse([1,2,3],X). X = [3,2,1] yes
a in-built predicate sort/2
| ?- sort([1,3,2],X). X = [1,2,3] yes
for any terms:
T1 = T2
true if terms are equal
T1 \= T2
true if terms are not equal
true if X matches the value of the arithmetic expression Expr:
X is Expr
true if the values of the arithmetic expressions Expr1 and Expr2 are equal:
Expr1 =:= Expr2
the complementary relation:
Expr1 =\= Expr2
true if terms are identical:
Term1 == Term2
that is, they have exactly the same structure and all the corresponding components are the same. the complementary relation:
Term1 \== Term2
| ?- X = myatom, read(Y), X = Y. myatom. X = myatom Y = myatom yes | ?- X = myatom, read(Y), X = Y. youratom. no | ?-
T1 < T2
T1 =< T2
T1 > T2
T1 >= T2
there are built-in procedures for these ops: + - * / mod/2
calculation triggers by built-in operator is
and also by comparison operators
| ?- 8 is 6 + 2. yes | ?- 12 is 6 * 2. yes | ?- -2 is 6 - 8. yes | ?- 3 is 6 / 2. yes | ?- R is mod(7, 2), write(R). 1 R = 1 yes
there is also predicate is/2
which is equivalent to op is
| ?- is(X,2 + 3). is(X,2 + 3). X = 5 yes
% file ddd.pl add_3_and_double :- read(X), Y is (X + 3) * 2, write(Y). len([], 0). len([_ | T], N) :- len(T, X), N is X + 1.
| ?- consult('ddd.pl'). compiling /home/../ddd.pl for byte code... /home/../ddd.pl compiled, 2 lines read - 607 bytes written, 14 ms yes | ?- add_3_and_double. 23. 52 yes | ?- X = [1, a, 5], len(X, Y), write(Y). 3 X = [1,a,5] Y = 3 yes | ?- is(X, +(3, 2)). X = 5 yes
% file eee.pl accLen([], A) :- write(A). accLen([_|T], A) :- ANew is A + 1, accLen(T, ANew). leng(List) :- accLen(List,0). accMax([H|T],A,Max) :- H > A, accMax(T,H,Max). accMax([H|T],A,Max) :- H =< A, accMax(T,A,Max). accMax([],A,A). max(List,Max) :- List = [H|_], accMax(List,H,Max).
| ?- [eee]. compiling /home/../eee.pl for byte code... /home/../eee.pl compiled, 5 lines read - 865 bytes written, 14 ms yes | ?- X = [1,a,5,man(juda)], accLen(X,0). 4 X = [1,a,5,man(juda)] yes | ?- X = [1,a,5,man(juda)], leng(X). 4 X = [1,a,5,man(juda)] yes | ?- max([4,1,52,-73,6],X). X = 52 ? yes
asserta(Clause).
converts the term Clause to a clause and then adds it to the current internal database. the clause is inserted before the first clause of the predicate. if the predicated is undefined it is created
assertz(Clause).
converts the term Clause to a clause and then adds it to the current internal database. the clause is inserted after the last clause of the predicate. if the predicated is undefined it is created
retract(Clause).
erases the first clause of the database that unifies with Clause. removing all clauses of a procedure does not erase the procedure definition. to achieve this use abolish/1
abolish(Pred/Arity).
removes from the database the procedure whose predicate indicator is Pred and arity is equial to Arity
p(t1,t2,...tn) -> yesway(tc1,...) ; noway(te1,...) .
example:
pass(auckland, hamilton, bus). pass(bangkok, auckland, plane). pass(frankfurt, bangkok, plane). pass(frankfurt, singapore, plane). pass(hamilton, raglan, bus). pass(losAngeles, auckland, plane). pass(metz, frankfurt, train). pass(metz, paris, train). pass(paris, losAngeles, plane). pass(saarbruecken, frankfurt, train). pass(saarbruecken, paris, train). pass(valmont, metz, bus). pass(valmont, saarbruecken, bus). travel(X,Y) :- pass(X, Y, T) -> write([T, X, Y]), ! , nl ; pass(X, Z, T1) , pass(Z, Y, T2) -> write([T1, X, Z, T2, Z, Y]), !, nl ; pass(X, Z1, T1) , pass(Z1, Z2, T2) , pass(Z2, Y, T3) -> write([T1, X, Z1, T2, Z1, Z2, T3, Z2, Y]), !, nl ; pass(X, Z1, T1) , pass(Z1, Z2, T2) , pass(Z2, Z3, T3) , pass(Z3, Y, T4) -> write([T1, X, Z1, T2, Z1, Z2, T3, Z2, Z3, T4, Z3, Y]), !, nl .
findall(Object, Goal, List).
produces a List of all Object that satisfy the Goal
/* file mydb.pl */ tab1('Aaa'). tab1('Bbb'). tab1('Ccc').
now:
| ?- consult(mydb). compiling /home/.../Prolog/mydb.pl for byte code... /home/.../Prolog/mydb.pl compiled, 3 lines read - 350 bytes written, 12 ms yes | ?- findall(X,tab1(X),L), length(L,N). L = ['Aaa','Bbb','Ccc'] N = 3 yes | ?-
in source file 'levi.pl':
%% hasband clan, wife clan, offspring clan aliance(a , b , c). aliance(b , c , d). aliance(c , d , a). aliance(d , a , b). testM(X) :- %% male - grandpa and grandchild aliance(X, _, Y), aliance(Y, _, not(X)), !. testF(X) :- %% female - grandgrandgrandma and grandgrandgrandchild aliance(_, X, Y), aliance(_, Y, Z), aliance(_, Z, K), aliance(_, K, not(X)), !.
and now in Prolog repl:
| ?- [levi]. [levi]. compiling /home/Prolog/levi.pl for byte code... /home/Prolog/levi.pl compiled, 32 lines read - 3311 bytes written, 13 ms yes | ?- testM(X). testM(X). no | ?- testF(X). testF(X). no