% A sample database. % marks comments % in file family.P % FACTS male(bob). % bob is male parent(jill, bill). % jill is parent of bill parent(bob, bill). % RULES father(TheDad, TheChild) :- parent(TheDad, TheChild), male(TheDad). % TheDad is the father of TheChild % if TheDad is the parent of TheChild and TheDad is male % Use meaningful variable names: % father(X, Y) :- parent(X, Y), male(X). % X is the father of Y if X is the parent of Y % and X is male % ":-" read as "if" % "," read as "and"
>/usr/local/bin/xsb % prolog prompt is ?- ?- [family]. % load file family.P yes % It worked ?- male(bob). % Is bob male? yes ?- male(jill). no ?- male(tom) no ?- female(bob) % Not in database Undefined predicate female/1 ?- parent(bob) % Not in database Undefined predicate parent/1 ?- parent(bob, bill). % match yes ?- father(bob, bill). % uses the rule! yes ?- halt. % or use ^D >
assert(male(joe)).Another way to do this is shown here.
?- [family]. yes ?- trace. yes ?- father(bob, bill). 0 Call: father(bob, bill) 1 Call: parent(bob, bill) 1 Exit: parent(bob, bill) 2 Call: male(bob) 2 Exit: male(bob) 0 Exit: father(bob, bill) yes
Variables can also be used in queries.
?- male(X). % Who is male? X = bob yes ?- parent(X, bill). % Multiple answers X = jill, % Type any characters X = bob; % Another answer no % No more answers findall(X, parent(X, bill), L). % ALL ANSWERS L = [jill, bob] yes ?- father(X, X). % No one is father of himself no % Both X's stand for the same thing
?- father(bob, Child). % bob is father of whom Child = bill yes ?- father(bob, bill). 0 Call: father(bob, Child) 1 Call: parent(bob, Child) 1 Exit: parent(bob, bill) 2 Call: male(bob) 2 Exit: male(bob) 0 Exit: father(bob, bill) yes
?- father(Dad, bill). % Who is father of bill Dad = bob yes ?- father(bob, bill). 0 Call: father(Dad, bill) 1 Call: parent(Dad, bill) 1 Exit: parent(jill, bill) % Jill is a parent of bill 2 Call: male(jill) % Is jill male? 2 Fail: male(jill) % No 1 Redo: parent(jill, bill) % Prolog tries to find another parent 1 Exit: parent(bob, bill) 3 Call: male(bob) 3 Exit: male(bob) 0 Exit: father(bob, bill) yes
parent(jack, jill). parent(jack, joe). parent(joe, janet). male(jack). male(joe). father(TheDad, TheChild) :- parent(TheDad, TheChild), male(TheDad). grandfather(TheGD, TheGC) :- father(TheGD, AParent), parent(AParent, TheGC ).
grandparent(X) :- parent(X, Y), parent(Y, Z).generates a warning that Z is a singleton variable since it is never used after it is instantiated.
grandparent(X) :- parent(X, Y), parent(Y, _).
?- X is 2 + 3. X = 5 yes ?- 8 is 7 + 1. yes ?- 7 + 1 is 8. % Only RHS is evaluated no ?- 7 + 1 is 7 + 1. % Neither side is evaluated yes
?- X is 9, Y is X + 3. % Instantiate and use X X = 9 Y = 12 yes ?- X is 9, Y is X + X. X = 9 Y = 18 yes ?- X is 9, Y is 18, Y is X + X. X = 9 Y = 18 yes ?- X is 9, Y is 10, Y is X + X. no ?- X is 9, X is X + X. no
?- Y is X + 3. Error: Unbound variable in arithmetic expression Aborting... ?- 5 is X + 3. % Try to instantiate X to 2 Error unbound variable in arithmetic expression Aborting... ?-
?- 2 = 2. yes ?- X = 2, Y = 5, X=Y. % Instantiate and test no ?- X = 5, Y is 2 + 3, X=Y. X = 5 Y = 5 yes ?- X = Y, Y = 3, Z is X+X. % X and Y share X = 3 Y = 3 Z = 6 yes ?- 8 = 7 + 1. % will not cause evaluation no ?- 7 + 1 = 7 + 1. % +(7,1) = +(7,1). yes
?- A=7, A > 5. yes ?- A=4, A > 5. no ?- A=4, A > B. Error: Unbound variable in arithmetic expression
X is 1, Y is 2, Z is 5, Z > X+Y, X < Z + Y. X = 1 Y = 2 Z = 5 yes
fac(1, 1). fac(N, F) :- N>1, D is N - 1, fac(D, P), F is N * P.
fac(4, 24) :- 4>1, 3 is 4 - 1, fac(3, 6), 24 is 4 * 6.
?- fac(3, X) % X and F share 0 Call: fac(3, X) % N is 3 1 Call: 3 > 1 1 Exit: 3 > 1 2 Call: 2 is 3 - 1 % D is 2 2 Exit: 2 is 3 - 1 3 Call: fac(2, F') % fac(N', F') %% New N and F: N' is 2 4 Call: 2 > 1 4 Exit: 2 > 1 5 Call: 1 is 2 - 1 % D' is 1 5 Exit: 1 is 2 - 1 6 Call: fac(1, F'') % fac(N'', F'') %% New N and F: N'' is 1 6 Exit: fac(1, 1) % F'' is 1 7 Call: 2 is 2 * 1 % F' is N' * F'' 7 Exit: 2 is 2 * 1 % F' is N' * F'' 3 Exit: fac(2, 2) % New N and F 8 Call: 6 is 3 * 2 % F is N * F' 8 Exit: 6 is 3 * 2 % F is N * F' 0 Exit: fac(3, 6) % New N and F: N' is 2
fac(1, 1). fac(N, F) :- N>1, D is N - 1, fac(D, P), F is N * P. facdemo1(X) :- fac(X,N), write(N). facdemo2 :- read(X), fac(X,N), write(N). /* Terminate input with a period */ facdemo2 :- read(X), facdemo1(X).
fib(0,1). /* Two base cases */ fib(1,1). fib(N, Result) :- N>1, NM1 is N - 1, NM2 is N - 2, fib(NM1, Result1), /* Recursive */ fib(NM2, Result2), Result is Result1 + Result2. fibdemo1(N) :- fib(N, Result), write(Result). fibdemo2 :- read(N), fib(N, Result), write(Result).
% Initial conditions can be passed to base case % as in fib(0)=fib0, fib(1)=fib1, fn = fn-1 + fn-2 % Example: fib3(4, 2, 9, X) gives X=31 % since 11 + 20 = 42 fib3(0, Fib0, _, Result) :- Result=Fib0. fib3(1, _, Fib1, Result) :- Result=Fib1. fib3(N, Fib0, Fib1, Result) :- N >1, NM1 is N - 1, NM2 is N - 2, fib3(NM1, Fib0, Fib1, Result1), fib3(NM2, Fib0, Fib1, Result2), Result is Result1 + Result2.
% Fac and fib calculate results as the % recursive calls return % Results can also be calcuated as calls are made % and the final result is returned from base case % Example: division by repeated subtraction: % Q = N / D % This divide calculates after the returns div1(N, D, Q) :- N >= 0, D > N, Q=0. div1(N, D, Q) :- D > 0, N >= D, NMD is N - D, div1(NMD, D, Q1), Q is Q1 + 1. % This divide calculates as the recursive calls % are made and passes result back % It needs a helper rule to initialize P div2(N, D, P, Q) :- N > 0, D > N, Q=P. div2(N, D, P, Q) :- D > 0, N >=D, NMD is N-D, PP1 is P+1, div2(NMD, D, PP1, Q). div3(N, D, R) :- div2(N, D, 0, R).
?- father(bob, Y). Y=bill yes ?- father(X, bill). X=bob yes
?- fib(X, 1). X=0, X=1, Arithmetic exception % NM1 is N-1 aborts Aborting... ?- fib(X, 2). Arithmetic exception % NM1 is N-1 aborts Aborting...
alive(_). % Everything is alive
parent(X) :- father(X) ; mother(X). it_major(X) :- cs_major(X). it_major(X) :- is_major(X).
parent(X) :- father(X) ; mother(X). % Define father and mother before or after this
parent(bob, bill). parent(bob, sam). ?- parent(bob, X).
% This version works (if possible) % gives stack overflow if not possible ancestor(Ances, Descend) :- parent(Ances, Descend). ancestor(Ances, Descend2) :- ancestor(Ances, Descend1), parent(Descend1, Descend2). parent(adam, bob). parent(bob, carl). ancestor(adam, carl). % Succeeds % This version always overflows the stack ancestor(Ances, Descend2) :- ancestor(Ances, Descend1), parent(Descend1, Descend2). ancestor(Ances, Descend) :- parent(Ances, Descend). parent(adam, bob). parent(bob, carl). ancestor(adam, carl). % Stack overflow
num1(0). num1(X) :- num1(W), X is W + 1. % num1(n) succeeds for any non-negative n % num1(X) finds 0, 1, 2, ... num2(X) :- num2(W), X is W + 1. num2(0). % num2(0) abort % num2(1) infinite stack overflow % num2(X) infinite stack overflow num3(0). num3(X) :- W is X - 1, num3(W). % num3(n) succeeds for any non-negative n % num3(X) finds 0 and aborts on another num4(X) :- num4(W), X is W + 1. num4(0). % num4(0) aborts % num4(1) infinite stack overflow % num4(X) aborts
.(a, .(b, .(c, [])))
X = [a, b] % X matches whole list Y = [] % Y is empty list [X, Y] = [a, b] % X=a, Y=b [X, Y, Z] = [a, b, c] % X=a, Y=b, Z=c [X,Y,Z] = [a, [1,2,3], c] % X=a, Y=[1,2,3], Z=c
[X|Y] = [a, b] % X=a, Y=[b] [X|Y] = [a] % X=a, Y=[] [X|Y] = [] % Fails. List must have a head [X|Y] = [a, b, c] % X=a, Y=[b,c] [W, X | Y] = [a, b, c, d] % W=a, X=b, Y=[c,d]
[X, [Y|Z]] = [1,2,3,4,5,6]. % fails - what would it match [X, Y|Z] = [1,2,3,4,5]. % X=1, Y=2, Z=[3,4,5] [X, Y|Z, A] = [1,2,3,4,5]. % Syntax error [X|Y] = [ [] ]. % X=[], Y=[] [[9,Y] | Z] = [[X,2], [3,4]]. % Y=2, Z=[[3,4]], X=9 [2|X] = [2, 3]. % X=[3] % a strange example (SKIP) %.(X, Y) = (2, .(3, .(4, []))) [X |Y] = [2|[3,4]]. % X=2, Y=[3,4] % [2|3] is not really a list! % This works, but is not recommended: %.(2, X) = .(2, 3) % .(2, 3) is NOT a list [2|X] = [2|3]. % X=3
% Assert some facts p([1,2,4]). p([a,b,c,[d,e]]). % Query those facts ?- p([X|Y]). X=1, Y=[2,4] ; X=a, Y=[b,c,[d,e]] ; no ?- p([_, _, _, [X|Y]]). X=d, Y=[e] ; no ?- p([X | [Y | Z]]). X=1, Y=2, Z=[4] ; X=a, Y=b, Z=[c,[d,e]] ; no
printlist([]) :- nl. printlist([H|T]) :- write(H), printlist(T). % Reverse print list? Trace?? % Notice how we split apart the list in the parameter! %member: what is the base case? member(X, [X|_]). member(X, [_|L]) :- member(X,L). % Trace and fill in info append([], List, List). append([H|L1], L2, [H|L3]) :- append(L1, L2, L3). %append: build the list as append returns %append: what if the base is append(List, [], List) rev([],[]). rev([H|T], List) :- rev(T, List2), append(List2, [H], List).
il1(Begin, End, L). - Succeeds if L is a list of integers from Begin
to End
, inclusive
il2
and il3
are similar with different implementations il1(2, 5, [2,3,4,5])
succeeds
il1(B, E, L) :- B > E, L = []. il1(B, E, L) :- B =< E, BP1 is B+1, il1(BP1, E, L1), append([B], L1, L). il2(B, E, []) :- B > E. il2(B, E, L) :- B =< E, BP1 is B+1, il2(BP1, E, L1), L = [B | L1]. il3(B, E, []) :- B > E. il3(B, E, [B|L1]) :- B =< E, BP1 is B+1, il3(BP1, E, L1). % Test for each version test1 :- il1(2,5,L), L=[2,3,4,5], il1(-1, 2, [-1, 0, 1, 2]), il1(3,1,[]). test2 :- il2(2,5,L), L=[2,3,4,5], ... test3 :- il3(2,5,L), L=[2,3,4,5], ... % Test for all 3 versions test :- test1, test2, test3.