Note: in Prolog terminology constants are also referred to as "atoms."
| Standard Notation | Operator Notation |
|---|---|
| +(a,/(b,c)) | a+b/c |
| is(X, mod(34, 7)) | X is 34 mod 7 |
| <(+(3,4),8) | 3+4 < 8 |
| =(X,f(Y)) | X = f(Y) |
| -(3) | -3 |
| spy(/(foo,3)) | spy foo/3 |
| :-(p(X),q(Y)) | p(X) :- q(Y) |
| :-(p(X),','(q(Y),r(Z))) | p(X) :- q(Y),r(Z) |
:- module(_,_,[]). % v------- Infix operator, no associativity :- op(500,xfx,is_father_of). % ^---- Precedence = 500then these two facts:
% is_father_of(john, peter). % is_father_of(peter,jim).can be written as:
john is_father_of peter. peter is_father_of jim.Try:
?- is_father_of(X,Y).
?- op(500,xfx,is_father_of).(this happens by default if module/2 is used). Now we can do:
?- X is_father_of Y.
:- op(1100,fx,[load,mult,bne]).
:- op( 500,fx,@).
:- op(1200,xfx,:).
label1 : load @r3,r1.
load 5,r2.
mult r1,r2.
bne 0,label1. :- op( 1200, xfx, [ :-, --> ]). :- op( 1200, fx, [ :-, ?- ]). :- op( 1150, fx, [ dynamic, multifile, meta_predicate]). :- op( 1100, xfy, [ ; ]). :- op( 1050, xfy, [ -> ]). :- op( 1000, xfy, [ ',' ]). :- op( 900, fy, [ \+, spy, nospy ]). :- op( 700, xfx, [ =, \=, is, =.., ==, \==, @<, @>, @=<, @>=, =:=, =\=, <, >, =<, >= ]). :- op( 550, xfx, [ : ]). :- op( 500, yfx, [ +, -, #, /\, \/ ]). :- op( 400, yfx, [ *, /, //, rem, mod, <<, >> ]). :- op( 200, fy, [ +, -, \ ]). :- op( 200, xfx, [ ** ]). :- op( 200, xfy, [ ^ ]).
:- module(_, _).
grandparent(C,G) :-
parent(C,P),
parent(P,G).
parent(C,P) :-
father(C,P).
parent(C,P) :-
mother(C,P).
father(charles, philip).
father(ana, george).
mother(charles, ana). ?- grandparent(charles,X).
arithexpr := | num | + arithexpr | - arithexpr | ++ arithexpr | -- arithexpr | arithexpr + arithexpr | arithexpr - arithexpr | arithexpr * arithexpr | arithexpr // arithexpr | arithexpr / arithexpr | abs(arithexpr) | sign(arithexpr) | float_integer_part(arithexpr) | float(arithexpr) | float_fractional_part(arithexpr) | arithexpr ** arithexpr | exp(arithexpr) | log(arithexpr) | sqrt(arithexpr) | sin(arithexpr) | cos(arithexpr) | atan(arithexpr) | [arithexpr] | $\ldots$Other arithmetic operators that can appear in arithmetic expressions (see manuals):
ISO-Prolog arithmetic
Try:
?- X is 3*3//2.
?- Z = 3//2, X is 3+Z.
Try:
?- X=3, Y=4, Y < X+1.
?- X=3, Y=4, X is Y+1.
?- X=3, Y=4, X =:= Y.
Try:
?- X is 3+Y.
?- Y=4, Y < a+1.
?- X is Z+1.
?- X=3, X =:= f(a).
:- module(_,_).
peano_factorial(0,s(0)).
peano_factorial(s(N),F) :-
peano_factorial(N,F1),
peano_times(s(N),F1,F).
peano_times(0,_,0).
peano_times(s(X),Y,Z) :-
peano_times(X,Y,W),
peano_plus(W,Y,Z).
peano_plus(0,Y,Y) :-
nat(Y).
peano_plus(s(X),Y,s(Z)) :-
peano_plus(X,Y,Z).
nat(0).
nat(s(X)) :- nat(X).?- peano_factorial(s(s(s(s(s(0))))),F).
?- peano_factorial(s(s(s(s(s(0))))),_).
?- peano_factorial(s(s(s(s(s(s(0)))))),_).
?- peano_factorial(s(s(s(s(s(s(s(0))))))),_).Takes long...
factorial(0,1).
factorial(N,F) :-
N > 0,
N1 is N-1,
factorial(N1,F1),
F is F1*N.Try:?- factorial(7,F).
?- factorial(1000,F).
?- factorial(100000,_).But:
?- factorial(N,6).Error!
wrong_factorial(0,1).
wrong_factorial(N,F) :-
N > 0,
N1 is N-1,
F is F1*N,
wrong_factorial(N1,F1).Try:?- wrong_factorial(3,F).Error!
Recovering some reversibility for the ISO-Prolog is/2 built-in
:- module(_,_). plus_plain(X,Y,Z) :- Z is X + Y.Try:
?- plus_plain(4,5,Z).Works, but cannot 'run backwards':
?- plus_plain(X,5,9).To recover some reversibility:
plus(X,Y,Z) :- number(X),number(Y), Z is X + Y. plus(X,Y,Z) :- number(X),number(Z), Y is Z - X. plus(X,Y,Z) :- number(Y),number(Z), X is Z - Y.Try:
?- plus(4,5,Z).
?- plus(X,5,9).But, it cannot do:
?- plus(X,Y,9).In fact, this should raise an error, rather than simply failing (we will see solutions for this later).
Try:
?- functor(t(b,a),F,A).
?- functor(Term,f,3).
?- functor(Vector,v,100).
Try:
?- _T=date(9,February,1947), arg(3,_T,X).
?- _T=date(9,February,1947), _T=date(_,_,X).The _ in _T instructs top level not to print the value of _T
?- functor(Array,array,5), arg(1,Array,black), arg(5,Array,white).
?- arg(2, [a,b,c,d], X).
The explanations in the comments in the code assume that we call with mode add_arrays(+,+,?), i.e., we provide the first two arrays and obtain the sum. Step through it in the debugger to see its operation!
:- module(_,_).
% Example of Structure Inspection: Arrays
add_arrays(A,B,C):-
functor(A,array,N), % Gets length N from array A
functor(B,array,N), % Checks that array B is of same length
functor(C,array,N), % Creates an array C to hold the result
add_elements(N,A,B,C).
add_elements(0,_A,_B,_C).
add_elements(I,A,B,C):-
I>0,
arg(I,A,AI),
arg(I,B,BI),
arg(I,C,CI),
CI is AI + BI,
I1 is I - 1,
add_elements(I1,A,B,C).Try:?- add_arrays(array(1,2,3),array(4,5,6),R).
?- add_arrays(array(1,2,3),array(4,5,6),array(5,7,9)).
?- add_arrays(array(1,2,3),array(4,5),R).
add_lists([],[],[]).
add_lists([X|Xs],[Y|Ys],[Z|Zs]):-
Z is X + Y,
add_lists(Xs,Ys,Zs).Try:?- add_lists([1,2,3],[4,5,6],R).
?- add_lists([1,2,3],[4,5,6],[5,7,9]).
?- add_lists([1,2,3],[4,5],R).
Allow functional notation:
:- module(_,_). % Example of Structure Inspection: Arrays, with some syntax :- use_package(fsyntax).Make @ be an infix operator:
:- op(250,xfx,@).Define @ as a call to arg/3:
T @ N := A :- arg(N,T,A).
% Same as: @(T,N) := A :- arg(N,T,A).
% or also: @(T,N,A) :- arg(N,T,A).Turn on evaluation of all occurrences of @/2::- fun_eval @ / 2.Define array/2 to hide the call to functor:
array(A,N) :- functor(A,array,N).Turn on evaluation of arith. expressions (e.g., I-1):
:- fun_eval arith(true).
add_arr(A,B,C) :-
array(A,N),
array(B,N),
array(C,N),
add_els(N,A,B,C).
add_els(0,_,_,_).
add_els(I,A,B,C) :-
I>0,
C@I is A@I + B@I, % <- Using our definition of @/2
add_els(I-1,A,B,C). ?- add_arr( array(1,2,3), array(4,5,6), R).
?- add_arr( array(1,2,3), array(4,5,6), array(5,7,9)).
?- add_arr( array(1,2,3), array(4,5),R).(Should fail - or, better, raise error.)
Example: Prime numbers up to N, using Eratosthenes sieve.
(Coded using the functional, loops, and arrays packages)
:- module(_, _, [functional,loops,arrays]).
:- use_module(library(arrays/arrays_log)).
primes(N) := Res :-
% Initialize the array with n+1 values to access until index n
A = ~new_array_log,
for (I in 2 .. N) { A[I] := true },
% We cross out the non primes
for (I in 2 .. ~floor(sqrt(N))) { % Loop goes until square root of N
if (A[I] == true) { % If a[i] is prime we cross out its multiples
for (J in I*I .. I .. N) { A[J] := false }
}
},
% We take the primes from the sieve and put them into a list
Res = ResTail,
for (K in 2 .. N) {
if (A[K] == true) { accum(!ResTail,K) }
},
ResTail = [].
accum(!R, X) :- R = [X|Tail], R := Tail.Try:?- primes(10, Ps).
?- primes(100, Ps).
?- primes(10000, _L), length(_L,MPrimes).
:- module(_,_).
% Example of Structure Inspection: Subterm
subterm(Term,Term). % a) A term is always a subterm of itself
subterm(Sub,Term):- % b) The arguments are also subterms:
nonvar(Term), % - Check Term not a free variable
functor(Term,_F,N),% - N is the number of arguments of Term
n_to_one(N, J), % - J is a natural between N and 1
arg(J,Term,Arg), % - Arg is the J-th argument of Term
subterm(Sub,Arg). % - Sub are the subterms of Arg
n_to_one(N, N) :- N > 0.
n_to_one(N, X) :- N > 1, N1 is N-1, n_to_one(N1, X). ?- n_to_one( 4, N ).
?- subterm( f(a) , g(b,f(a)) ).
?- subterm( f(b) , g(b,f(a)) ).
?- subterm( g(b,f(a)) , g(b,f(a)) ).
?- subterm( X , g(b,f(a)) ).
?- subterm( f(X) , g(b,f(a)) ).
?- subterm( X , g(X,f(a)) ).
?- subterm( f(X) , g(b,f(X)) ).
Try:
?- date(9,february,1947) =.. L.
?- T =.. [date,9,february,1947].
?- _F = '+', X =.. [_F,a,b].(The _ in _F instructs top level not to print the value of _F.)
:- module(_,_).
% Extending derivative:
deriv(sin(X), X, cos(X)).
deriv(cos(X), X, -sin(X)).
% Chain rule:
deriv(FG_X, X, DF_G * DG_X):-
FG_X =.. [_, G_X],
deriv(FG_X, G_X, DF_G),
deriv(G_X, X, DG_X).Try:?- deriv(sin(cos(x)),x,D).
Conversion between strings and atoms
Try:
?- name(hello,S).
?- name(A,[104,101,108,108,111]).
?- name(A,"hello").
?- set_prolog_flag(write_strings,on).
?- name(hello,S).
Try:
?- X='1', atom(X), name(X,S), name(Y,S), number(Y).(Succeeds! Note that we start with the atom '1' and we end up with the number 1.)
Try:
?- atom_codes('1', L).?- atom_codes(1, L).
?- number_codes('1', L).?- number_codes(1, L).
?- number_codes(X, "1").
?- atom_codes(X, "1").
Choosing between two implementations based on calling mode, using meta-logical predicates (i.e., implementing reversibility "by hand").
:- module(_,_).
len([],0).
len([_|T],N) :-
len(T,TN),
N is TN+1. This allows us to write a better (tail recursive) version for create_list/2.
First, detect the mode and choose implementation:
mylength(Xs,N):-
var(Xs),
integer(N),
create_list(N,Xs).
mylength(Xs,N):-
nonvar(Xs),
compute_length(Xs,N).Create a list of length N (tail recursive):create_list(0,[]).
create_list(N,[_|Xs]):-
N > 0,
N1 is N - 1,
create_list(N1,Xs).Compute the length of the list (same as len/2 for now):compute_length([],0).
compute_length([_|T],N):-
compute_length(T,TN),
N is TN+1.Try:?- len([a,b,c],N).
?- len(L,3).
?- mylength([a,b,c],N).
?- mylength(L,3).
Choosing between two implementations based on calling mode, using meta-logical predicates (i.e., implementing reversibility "by hand").
First, detect the mode and choose implementation:
:- module(_,_).
mylength(Xs,N):-
var(Xs),
integer(N),
create_list(N,Xs).
mylength(Xs,N):-
nonvar(Xs),
compute_length(Xs,N).Create a list of length N (tail recursive):create_list(0,[]).
create_list(N,[_|Xs]):-
N > 0,
N1 is N - 1,
create_list(N1,Xs).Compute the length of the list (now also tail recursive):compute_length(L,N) :-
compute_length_(L,0,N).
compute_length_([],N,N).
compute_length_([_|T],A,N) :-
NA is A+1,
compute_length_(T,NA,N).Try:?- mylength([a,b,c],N).
?- mylength(L,3).
:- module(_,_).
% Example application of comparing non-ground terms
% (use of ==/2, \==/2, @>/2, ...)
subterm_ng(Sub,Term) :- % a) A term is a subterm of another
Sub == Term. % if they are identical.
subterm_ng(Sub,Term) :- % b) The arguments are also subterms:
nonvar(Term), % Check Term not a free variable
functor(Term,_F,N), % N is number of arguments of Term
n_to_one(N, J), % J is a natural between N and 1
arg(J,Term,Arg), % Arg is the J-th argument of Term
subterm_ng(Sub,Arg).% Sub are the subterms of Arg
n_to_one(N, N) :- N > 0.
n_to_one(N, X) :- N > 1, N1 is N-1, n_to_one(N1, X).Compare to the subterm/2 version with =/2 instead of ==/2 (below).Try (asking also for other solutions):
?- subterm_ng( f(a), g(b,f(a)) ).
?- subterm( f(a), g(b,f(a)) ).
?- subterm_ng( f(b), g(b,f(a)) ).
?- subterm( f(b), g(b,f(a)) ).
?- subterm_ng( g(b,f(a)), g(b,f(a)) ).
?- subterm( g(b,f(a)), g(b,f(a)) ).
?- subterm_ng( X, g(b,f(a)) ).
?- subterm( X, g(b,f(a)) ).
?- subterm_ng( f(X), g(b,f(a)) ).
?- subterm( f(X), g(b,f(a)) ).
?- subterm_ng( f(a), g(b,f(X)) ).
?- subterm( f(a), g(b,f(X)) ).
?- subterm_ng( f(X), g(b,f(X)) ).
?- subterm( f(X), g(b,f(X)) ).
?- subterm_ng( X, g(X,f(a)) ).
?- subterm( X, g(X,f(a)) ).
% Version using =/2:
subterm(Term,Term). % a) A term is always a subterm of itself
subterm(Sub,Term):- % b) The arguments are also subterms:
nonvar(Term), % Check Term not a free variable
functor(Term,_F,N),% N is the number of arguments of Term
n_to_one(N, J), % J is a natural between N and 1
arg(J,Term,Arg), % Arg is the J-th argument of Term
subterm(Sub,Arg).% Sub are the subterms of Arg :- module(_,_). % Example application of comparing non-ground terms % (use of ==/2, \==/2, @>/2, ...) % Inserting an item into an ordered list. insert_unif([], Item, [Item]). insert_unif([H|T], Item, [H|T]) :- H = Item. insert_unif([H|T], Item, [Item, H|T]) :- H @> Item. insert_unif([H|T], Item, [H|NewT]) :- H @< Item, insert_unif(T, Item, NewT).Try:
?- insert_unif([], a, L).
?- insert_unif([a,b,e], c, L).
?- insert_unif([a,b,e], X, L).
insert_ee([], Item, [Item]). insert_ee([H|T], Item, [H|T]) :- H == Item. insert_ee([H|T], Item, [Item, H|T]) :- H @> Item. insert_ee([H|T], Item, [H|NewT]) :- H @< Item, insert_ee(T, Item, NewT).Try:
?- insert_ee([], a, L).
?- insert_ee([a,b,e], c, L).
?- insert_ee([a,b,e], X, L).
| Class | Predicate | Explanation |
|---|---|---|
| I/O stream control | see(File) | File becomes the current input stream. |
| seeing(File) | The current input stream is File. | |
| seen | Close the current input stream. | |
| tell(File) | File becomes the current output stream. | |
| telling(File) | The current output stream is File. | |
| told | Close the current output stream. | |
| Term I/O | write(X) | Write the term X on the current output stream. |
| nl | Start a new line on the current output stream. | |
| read(X) | Read a term (finished by a full stop) from the current input stream and unify it with X. | |
| Character I/O | put_code(N) | Write the ASCII character code N. N can be a string of length one. |
| get_code(N) | Read the next character code and unify its ASCII code with N. |
?- tell(foo), write( f(g(a,[1,2,3])) ), told.We use the auxiliary predicate below to see the exact contents of foo:
?- set_prolog_flag(write_strings,on).
?- show_file(foo).
write_list_to_file(L,F) :-
telling(OldOutput), % Grab current output stream.
tell(F), write_list(L), told, % Write into F, close.
tell(OldOutput). % Reset previous output stream.
write_list([]).
write_list([X|Xs]):-
write(X),
% write_canonical(X),
write('.'),
nl,
write_list(Xs).Try:?- write_list_to_file([ f(a), m, g(k)],foo).
?- show_file(foo).
?- see(foo), read(X), seen.
?- see(foo).
?- read(X).
?- read(X).
?- read(X).
?- seen.
:- use_module(library(stream_utils)).
show_file(F) :-
file_to_string(F,L),
format("~s",[L]). | Class | Predicate | Explanation |
|---|---|---|
| I/O stream control | open(File,M,S) | Open File with mode M and return in S the stream associated with the file. M may be read, write or append. |
| close(S) | Close the stream ‘Stream’. | |
| Term I/O | write(S,X) | Write the term X on stream S. |
| nl(S) | Start a new line on stream S. | |
| read(S,X) | Read a term (finished by a full stop) from the stream S and unify it with X. | |
| Character I/O | put_code(S,N) | Write the ASCII character code N on stream S. |
| get_code(S,N) | Read from stream S the next character code and unify its ASCII code with N. |
write_list_to_file(L,F) :- telling(OldOutput), % Grab current output stream. tell(F), % Write into F. write_list(L), % Write a list of terms. told, % Close. tell(OldOutput). % Reset previous output stream. write_list([]). write_list([X|Xs]):- write(X), nl, write_list(Xs).
Execute in debugger to see how execution proceeds!
:- module(_,_). :- discontiguous([s/1, l/1, r/1, t/1]). main(A,X,Y) :- s(A), p(X,Y). s(1) :- noop. l(a) :- noop. s(2) :- noop. l(b) :- noop. r(8) :- noop. t(10) :- noop. r(9) :- noop. t(11) :- noop. m(e) :- noop. noop. p(X,_Y) :- l(X). p(X, Y) :- r(X), !, t(Y). p(X,_Y) :- m(X).If execution reaches the cut (!):
?- p(9,Y).
?- p(e,Y).
?- main(A,X,Y).
?- main(2,X,Y).
s(1). p(X,Y):- l(X), ... r(8). s(2). p(X,Y):- r(X), !, ... r(9). p(X,Y):- m(X), ...
:- module(_,_).
% Types of cuts - White and Green Cuts
% ------------------------------------
% Example:
white_max(X,Y,X) :-
X > Y,
!.
white_max(X,Y,Y) :-
X =< Y.Try:?- white_max(5,2,M).
?- white_max(2,5,M).
?- white_max(5,2,2).
address(X,Addr) :-
home_address(X,Addr),
!.
address(X,Addr) :-
business_address(X,Addr).
home_address(john,pfluggerville).
business_address(john,austin).
business_address(mary,boston).Try (look for all solutions):?- address(john,Addr).
?- address(mary,Addr).Another example:
member_normal(X,[X|_]).
member_normal(X,[_|T]) :-
member_normal(X,T).
member_check(X,[X|_]) :- !.
member_check(X,[_|T]) :-
member_check(X,T).Try (look for all solutions):?- member_normal(X,[1,2,3,4]).Multiple answers.
?- member_check(X,[1,2,3,4]).Only one answer.
?- member_normal(1,[1,2,1,4]), write('found a solution'), nl, fail.Note that it succeeds twice.?- member_check(1,[1,2,1,4]), write('found a solution'), nl, fail.Note that it succeeds once. But they can easily affect correctness - avoid when possible.
:- module(_,_).
% Types of cuts - Red Cuts
% ------------------------------------
red_max(X,Y,X) :-
X > Y,
!. % Red cut!
red_max(_X,Y,Y). % :-
% X =< Y. % Missing!Try:?- red_max(5,2,M).
?- red_max(2,5,M).
?- red_max(5,2,2).Note that this last one produces a wrong answer! Often because the program was written with only one mode in mind: max(+,+,-).
Compare to (white cut):
white_max(X,Y,X) :-
X > Y,
!.
white_max(X,Y,Y) :-
X =< Y.Try:?- white_max(5,2,M).
?- white_max(2,5,M).
?- white_max(5,2,2).
days_in_year( X,366):-
leap_year(X),
!.
days_in_year(_X,365).
leap_year(X):-
number(X),
0 is X mod 4.Some good answers:?- days_in_year(4,D).
?- days_in_year(3,D).
?- days_in_year(3,366).
?- days_in_year(4,366).But wrong answers to:
?- days_in_year(4,365).
?- days_in_year(Y,366).
:- module(_,_).
% Types of cuts - Red Cuts
% Useful tips regarding red cuts
% ------------------------------
red_max_delay_output(X,Y,M) :-
X > Y,
!,
M = X.
red_max_delay_output(_X,Y,Y).
% X =< Y.Try:?- red_max_delay_output(5,2,M).
?- red_max_delay_output(2,5,M).
?- red_max_delay_output(5,2,2).Now also correct answer to the last one (no).
if_then_else_max(X,Y,M) :- ( X>Y -> M=X ; M=Y).(if X>Y then M=X else M=Y)
Try:
?- if_then_else_max(5,2,M).
?- if_then_else_max(2,5,M).
?- if_then_else_max(5,2,2).Also correct answer to the last one (no).
:- module(_,_).
% Types of cuts - Red Cuts
% ------------------------
days_in_year(Y,366) :-
leap_year(Y),
!.
days_in_year(_Y,365).
leap_year(Y) :-
number(Y),
0 is Y mod 4.Try:?- days_in_year(4,D).
?- days_in_year(3,D).
?- days_in_year(3,366).
?- days_in_year(4,366).
?- days_in_year(4,365).
?- days_in_year(Y,366).The last two produce a wrong answer...
days_in_year_good(Y,D) :-
leap_year(Y),
!,
D = 366.
days_in_year_good(Y,D) :-
standard_year(Y),
D = 365.
standard_year(Y) :-
number(Y),
R is Y mod 4,
R \= 0.Try:?- days_in_year_good(4,D).
?- days_in_year_good(3,D).
?- days_in_year_good(3,366).
?- days_in_year_good(4,366).
?- days_in_year_good(4,365).
?- days_in_year_good(Y,366).
?- days_in_year_good(a,D).
days_in_year_delay_output(Y,D) :-
leap_year(Y),
!,
D = 366.
days_in_year_delay_output(_Y,365).Try:?- days_in_year_delay_output(4,D).
?- days_in_year_delay_output(4,365).
?- days_in_year_delay_output(4,366).
?- days_in_year_delay_output(Y,366).Note that the last one still produces a wrong answer! This is because we are probably thinking of a 'mode': that we provide the year and ask for the number of days.
days_in_year_moded(Y,_D) :-
var(Y),
!,
write('{ ERROR: the year must be bound. }\n'),
abort.
days_in_year_moded(Y,D) :-
leap_year(Y),
!,
D = 366.
days_in_year_moded(_Y,365).Try:?- days_in_year_moded(4,D).
?- days_in_year_moded(3,D).
?- days_in_year_moded(4,365).
?- days_in_year_moded(4,366).
?- days_in_year_moded(Y,366).
?- days_in_year_moded(a,D).
Load assertions and modes packages + run-time checking of assertions:
:- use_package([assertions,modes,rtchecks]).Use an assertion to state the expected mode:
:- pred days_in_year_moded_assrt(+int,-int).
% Or equivalently, without using modes:
% :- pred days_in_year_moded_assrt(Y,D) : (int(Y),var(D)).
days_in_year_moded_assrt(Y,D) :-
leap_year(Y),
!,
D=366.
days_in_year_moded_assrt(_Y,365).Try:?- days_in_year_moded_assrt(4,D).
?- days_in_year_moded_assrt(4,366).
?- days_in_year_moded_assrt(4,365).
?- days_in_year_moded_assrt(Y,366).
?- days_in_year_moded_assrt(a,D).
:- module(_,_). % Meta-calls (call/1) and implementing apply % ------------------------------------------ r(X) :- call(X). q(a,1). q(b,2).Try (ask also for more solutions):
?- G = q(a,Y), r(G).
?- G = member(Y,[1,2,3]), r(G).
apply(P,Args) :-
G =.. [P|Args],
call(G).Try:?- P = q, apply(P,[a,Y]).
?- P = q, apply(P,[X,Y]).
maptuples(_P,[]).
maptuples(P,[Tuple|RTuples]) :-
apply(P,Tuple),
maptuples(P,RTuples).Try:?- maptuples(q,[[a,X],[b,Y]]).
?- maptuples(append, [ [ [a],[c,d], X ], [ X, [e,f], Y ], [ X, Y, Z ] ]).
Given:
:- module(_,_). % Meta-calls: call/n % ------------------ q(a,1). q(b,2).We first load hiord into the top level:
?- use_package(hiord).Try:
?- P = q, call(P,X,Y).
?- P = q(a), call(P,Y).
?- P = append, call(P,[1,2],[3,4],Y).
?- P = append(X,Y), call(P,[1,2,3,4]).
Given:
plus(X,Y,Z) :- number(X),number(Y), Z is X + Y. plus(X,Y,Z) :- number(X),number(Z), Y is Z - X. plus(X,Y,Z) :- number(Y),number(Z), X is Z - Y.Try:
?- use_module(library(hiordlib)).
?- maplist(plus, [1,2,3], [4,5,6], R).
?- maplist(plus, [1,2,3], L2, [5,7,9]).
?- maplist(append, [ [a,b], [1,2] ], [ [c,d], [3,4] ], Z).
?- maplist(append, [ [a,b], [1,2] ], Y, [[a,b,c,d],[1,2,3,4]] ).
?- maplist(append, [ [a], X, X ], [ [c,d], [e,f], Y ], [ X, Y, Z] ).
:- module(_,_). % Some additional functionality via the hiord package % --------------------------------------------------- q(a,1). q(b,2).
Load hiord package in top level:
?- use_package(hiord).Try (ask for more solutions):
?- P = q, P(X,Y).
?- P = append, P([1,2],[3,4],Y).
?- P = append(X,Y), P([1,2,3,4]).
?- P = { _(X,Y) :- Y is X+1 }, P(3,R). likes(bill, cider). likes(dick, beer). likes(tom, beer). likes(tom, cider). likes(harry, beer). likes(jan, cider).
?- findall(X, likes(X,Y), S). S = [bill,dick,tom,tom,harry,jan] ? yes ?- findall(X, likes(X,water), S). S = [] ? yes ?-
?- findall(X, member(X,[d,a,b,c,b,d]), L).
?- setof(X, member(X,[d,a,b,c,b,d]), L).
?- bagof(X, member(X,[d,a,b,c,b,d]), L).
?- findall(X, (member(X,[d,a,b,c,b,d]), X @< c), L).
likes(bill, cider). likes(dick, beer). likes(tom, beer). likes(tom, cider). likes(harry, beer). likes(jan, cider).
Try (asking for more solutions):
?- findall(X, likes(X,Y), S).
?- findall(X, likes(X,water),S).Note the empty list.
?- setof(X, likes(X,Y), S).
?- setof(X, Y^likes(X,Y), S).
?- setof(X, likes(X,water), S).Note that it fails.
?- bagof(X, likes(X,Y), S).
?- bagof(X, Y^likes(X,Y), S).
?- bagof(X, likes(X,water),S).Note that it fails.
?- findall( Y-L , setof(X,likes(X,Y),L), Pairs).
?- findall(beer_lover(X), likes(X,beer), S).
?- setof((Y,S), setof(X, likes(X,Y), S), SS).
subset([],[]).
subset([X|Xs],[X|Ys]) :-
subset(Xs,Ys).
subset([_|Xs],Ys) :-
subset(Xs,Ys).
powerset(Set,Pset) :-
setof(X,subset(Set,X),Pset).Try (asking for more solutions):?- subset([1,2,3],S).
?- powerset([1,2,3],Pset).
:- module(_,_). % Meta-calls and cut: Negation as failure % --------------------------------------- not( Goal) :- call(Goal), !, fail. not(_Goal).
Try:
?- not( member(c, [a, k, l]) ).
?- \+ member(c, [a, k, l]).
unmarried_student(X) :-
\+ married(X),
student(X).
student(joe).
married(john).Note that Joe is an unmarried student, but John is NOT an unmarried student!Try:
?- unmarried_student(joe).
?- unmarried_student(john).
?- unmarried_student(X).This last one is wrong, an unmarried student does exist!
Try:
?- ground(unmarried_student(joe)).
?- ground(unmarried_student(X)).
overlap(S1,S2) :- % S1 and S2 overlap if they share an element
member(X,S1), member(X,S2).
disjoint(S1,S2) :- \+ overlap(S1,S2).Try:?- disjoint([1,2,3,4],[a,b,c]).
?- disjoint([1,2,3,4],[2,4,c]).
:- module(_,_).
% Meta-calls and cut: Negation as failure -- ensuring correctness
% ---------------------------------------------------------------
unmarried_student(X) :-
\+ married(X),
student(X).
student(joe).
married(john).Try:?- unmarried_student(X).Which we know is wrong, since an unmarried student does exist.
not_(G) :-
ground(G), !,
\+ G.
not_(G) :-
write('ERROR: Non-ground goal in negation: '), write(G), nl,
abort.
unmarried_student_with_check(X) :-
not_(married(X)),
student(X).Try:?- unmarried_student_with_check(joe).
?- unmarried_student_with_check(john).
?- unmarried_student_with_check(X).
:- use_package([assertions,modes,rtchecks]).
:- pred not__(G) : ground(G). not__(G) :- \+ G.And we use this not__/1 in the example:
assrt_unmarried_student(X) :-
not__( married(X) ),
student(X).This will be checked, in this case dynamically (by rtchecks):?- assrt_unmarried_student(joe).
?- assrt_unmarried_student(X).
once(X) :- call(X), !.Try (asking for more alternatives):
?- member(X,[1,2,3]).
?- once(member(X,[1,2,3])).
:- module(_,_). % Meta-calls and cut: cut-fail % ---------------------------- myfail :- a=b.(It is available simply as fail).
We tell the compiler we are redefining the ground/1 built-in:
:- redefining(ground/1).Definition of ground/1 using cut and fail:
ground(Term) :-
var(Term),
!,
fail.
ground(Term) :-
nonvar(Term),
functor(Term,_F,N),
ground_(N,Term).
ground_(0,_T). % All subterms traversed
ground_(N,T) :-
N>0,
arg(N,T,Arg),
ground(Arg),
N1 is N-1,
ground_(N1,T).Try (also in the debugger):?- ground(a).
?- ground(X).
?- ground(f(a,f(X,d),b)).Comment out the first clause of ground/1 and guess what happens.
Try (also in the debugger):
?- ground(f(a,f(c,d),Z)).
:- module(_,_).Examples for dynamic predicates
Try (asking for more solutions):
?- p(X).
?- assert(p(a)).
?- p(X).
?- assert(p(b)).
?- p(X).
?- retract(p(a)).
?- retract(p(b)).
?- p(X).
?- abolish(p/1).
?- p(X).
related(3,4).It must be declared dynamic for it to be modifiable:
:- dynamic related/2.We define some operations on related/2:
relate_numbers(X,Y) :- assert(related(X,Y)). unrelate_numbers(X,Y) :- retract(related(X,Y)).Try:
?- related(3, 4).
?- related(1, 2).
?- relate_numbers(1, 2).
?- related(1, 2).
?- related(X, Y).
?- unrelate_numbers(1, 2).
?- related(1, 2).
?- abolish(related/2).
?- related(1,2).
:- dynamic app/3.
% Create the definition of append
define_app :-
assert( app([], X, X) ),
assert( ( app([X|Y], Z, [X|W]) :- app(Y,Z,W) ) ).
% Erase the definition of append
erase_app :-
abolish(app/3).Try:?- app([1,2],[3,4],Y).
?- erase_app.
?- app([1,2],[3,4],Y).
?- define_app.
?- app([1,2],[3,4],Y).
?- app(X,Y,[1,2,3,4]).
?- erase_app.
?- app(X,Y,[1,2,3,4]).
The Fibonacci sequence: 0, 1, and then: element n is element n-1 + element n-2,
i.e., 0 1 1 2 3 5 8 13 21 ...
:- module(_,_).
% Dynamic program modification example: using lemmas
% --------------------------------------------------
fib(0, 0).
fib(1, 1).
fib(N, F) :-
N > 1,
N1 is N - 1,
N2 is N - 2,
fib(N1, F1),
fib(N2, F2),
F is F1 + F2. :- use_package(fsyntax). :- fun_eval arith(true). ffib(0) := 0. ffib(1) := 1. ffib(N) := ~ffib(N-1) + ~ffib(N-2) :- N>1.
First, we define a table (with a dynamic predicate) that holds the first two elements, i.e., for N=0 and N=1:
:- dynamic lemma_fib/2. lemma_fib(0, 0). lemma_fib(1, 1).To compute the rest:
lfib(N, F) :-
% First check if we have the Nth element in the table,
% and we take it from there.
lemma_fib(N, F),
!.
lfib(N, F) :-
% Else, we compute the Nth number...
N > 1,
N1 is N - 1,
N2 is N - 2,
lfib(N1, F1),
lfib(N2, F2),
F is F1 + F2,
% ...and once we have it we record it:
assert(lemma_fib(N, F)). Try (compare the computation time, adjust the values for your CPU):?- fib(30,Y).
?- fib(31,Y).
?- fib(32,Y).
?- fib(35,Y).
?- lfib(30,Y).
?- lfib(35,Y).
?- lfib(200,Y).
?- lfib(1000,Y).
We use this (Ciao-specific) version of the dynamic package that makes dynamic clauses visible to clause/2:
:- module(_,_,[]). % Meta-interpreters % ----------------- :- use_package(dynamic_clauses).
:- dynamic lappend/3. lappend([],X,X). lappend([X|Y],Z,[X|W]) :- lappend(Y,Z,W).
Try (ask for several solutions):
?- clause(lappend(A,B,C),Body).
solve( true ) :- !. solve( (A,B) ) :- !, solve(A), solve(B). solve( A ) :- clause(A,B), solve(B).Try (asking for multiple solutions):
?- solve(lappend([1,2],[3,4],L)).
?- solve(lappend(X,Y,[1,2,3,4])).
solve( true ) :- !. solve( (A,B) ) :- !, solve(A), solve(B). solve( A ) :- clause(A,B), solve(B).can be easily extended to do many tasks: tracing, debugging, explanations in expert systems, implementing other computation rules, ...
Declare lappend/3 dynamic, and thus visible to clause/2:
:- module(_,_,[]). % Meta-interpreters: extending the basic meta-interpreter % ------------------------------------------------------- % Ciao-specific: version of 'dynamic' package that makes dynamic % clauses visible to `clause/2` :- use_package(dynamic_clauses). :- dynamic lappend/3. lappend([],X,X). lappend([X|Y],Z,[X|W]) :- lappend(Y,Z,W).A version of the meta-interpreter that uses an extra argument to count the number of (forward) steps:
csolve( true, 0) :- !. csolve( (A,B), N) :- !, csolve(A,NA), csolve(B,NB), N is NA+NB. csolve( A, N) :- clause(A,B), csolve(B,N1), N is N1+1.Try:
?- csolve(lappend([1,2],[3,4],L),N).
?- csolve(lappend([1,2,a,b],[3,4],L),N).
?- csolve(lappend([1,2],[3,4,a,b],L),N).What does the cost (number of steps) of a call to lappend/3 depend on?
dlist(X-X). dlist([_|DL]-Y) :- dlist(DL-Y).
append_dl(B1-E1,B2-E2,B3-E3) :- B3=B1, E3=E2, B2=E1.Or, more compactly: append_dl(X-Y,Y-Z,X-Z).
?- L = [1,2,3|T]-T, L = _-T, T = [4,5].
dlist(X-X). dlist([_|DL]-X) :- dlist(DL-X).(note that we could also need var/1 and ==/2 checks.)
Try (ask for multiple solutions):
?- dlist(L).
?- L1 = [1,2,3|X], L2 = [4,5|Y], L2=X.But note that we have modified the tail of the first list: we cannot append to it again.
append_dl(B1-E1,E1-E2,B1-E2).Try:
?- append_dl( [1,2,3|X]-X, [4,5|Y]-Y, L).L has the resulting (appended) difference list.
But note that we have modified the first list: we cannot append to it again.
?- append_dl(L-X,[4,5|Y]-Y,[1,2,3,4,5|Z]-Z).
Checking:
?- append_dl( [1,2,3|X]-X, [4,5|Y]-Y, [1,2,3,4,5|Z]-Z).Subtracting:
?- append_dl( L-X, [4,5|Y]-Y, [1,2,3,4,5|Z]-Z).
?- append_dl( L1-X, L2-Y, [1,2,3,4,5|Z]-Z).But only one solution, and we cannot append again.
:- module(_,_).
qsort([],[]).
qsort([X|L],S) :- % Take first element of list in X
partition(L,X,LS,LB), % LS are the elements of L < X
% LB are the elements of L >= X
qsort(LS,LSS), % LSS is LS sorted
qsort(LB,LBS), % LBS is LB sorted
append(LSS,[X|LBS],S). % We append the small ones sorted to
% the big ones sorted (w/X in front)
partition([],_P,[],[]).
partition([E|R],P,[E|Smalls],Bigs) :- % Take first element E
E < P, % If E < P add to list of smaller ones
partition(R,P,Smalls,Bigs).
partition([E|R],P,Smalls,[E|Bigs]) :-
E >= P, % If E >= P add to list of larger ones
partition(R,P,Smalls,Bigs). ?- qsort([5,2,1,3,7,6], SL).
:- module(_,_).
qsort([],[]).
qsort([X|L],S) :- % X=5, L=[2,1,3,7,6]
partition(L,X,LS,LB), % LS=[2,1,3]
% LB=[7,6]
qsort(LS,LSS), % LSS=[1,2,3]
qsort(LB,LBS), % LBS=[6,7]
append(LSS,[X|LBS],S). % call: append([1,2,3],[5,6,7],S)
% S=[1,2,3,5,6,7]
partition([],_P,[],[]).
partition([E|R],P,[E|Smalls],Bigs) :-
E < P,
partition(R,P,Smalls,Bigs).
partition([E|R],P,Smalls,[E|Bigs]) :-
E >= P,
partition(R,P,Smalls,Bigs). ?- qsort([5,2,1,3,7,6], SL).
:- module(_,_).
qsort_dl(L,SL) :- % L = [5,2,1,3,7,6]
qsort_dl_(L,SL-SLE), % SL = [1,2,3,5,6,7|SLE]
SLE = []. % SL = [1,2,3,5,6,7]
qsort_dl_([],SLE-SLE).
qsort_dl_([X|L],SL-SLE) :- % X = 5, L = [2,1,3,7,6]
partition(L,X,S,B), % S = [2,1,3], B = [7,6]
qsort_dl_(S,SS-SSE), % SS = [1,2,3|SSE]
qsort_dl_(B,BS-BSE), % BS = [6,7|BSE]
SSE = [X|BS], % SSE = [5,6,7|BSE]
SL = SS, % SL = [1,2,3,5,6,7|BSE]
SLE = BSE. % SL = [1,2,3,5,6,7|SLE]?- qsort_dl([5,2,1,3,7,6], SL).Run it in the debugger! (Partition is same as in std. qsort:)
partition([],_P,[],[]).
partition([E|R],P,[E|Smalls],Bigs) :- % Take first element E
E < P, % If E < P add to list of smaller ones
partition(R,P,Smalls,Bigs).
partition([E|R],P,Smalls,[E|Bigs]) :-
E >= P, % If E >= P add to list of larger ones
partition(R,P,Smalls,Bigs). :- module(_,_).
qsort_dl(L,SL) :-
qsort_dl_(L,SL-[]).
%
qsort_dl_([],SLE-SLE).
qsort_dl_([X|L],SL-SLE) :-
partition(L,X,S,B),
qsort_dl_(S,SL-[X|BS]),
qsort_dl_(B,BS-SLE).?- qsort_dl([5,2,1,3,7,6], SL).Run it in the debugger! (Partition is same as in std. qsort:)
partition([],_P,[],[]). partition([E|R],P,[E|Smalls],Bigs) :- E < P, partition(R,P,Smalls,Bigs). partition([E|R],P,Smalls,[E|Bigs]) :- E >= P, partition(R,P,Smalls,Bigs).
:- module(_,_).
qsort_dl(L,SL) :-
qsort_dl_(L,SL,[]).
%
qsort_dl_([],SLE,SLE).
qsort_dl_([X|L],SL,SLE) :-
partition(L,X,S,B),
qsort_dl_(S,SL,[X|BS]),
qsort_dl_(B,BS,SLE).?- qsort_dl([5,2,1,3,7,6], SL).Run it in the debugger! (Partition is same as in std. qsort:)
partition([],_P,[],[]). partition([E|R],P,[E|Smalls],Bigs) :- E < P, partition(R,P,Smalls,Bigs). partition([E|R],P,Smalls,[E|Bigs]) :- E >= P, partition(R,P,Smalls,Bigs).
:- module(_,_).
% :- use_package(sr/bfall).
myphrase(P) :-
% An article (A) must be at beginning of P, T1 is the rest:
append_(A,T1,P), article(A),
append_(S1,T2,T1), spaces(S1), % Spaces must follow
append_(N,T3,T2), noun(N), % A noun must follow
append_(S2,V,T3), spaces(S2), % Spaces must follow
verb(V). % Must end with a verb
article([a]).
article([t,h,e]).
spaces([' ']).
spaces([' ' | T]) :-
spaces(T).
noun([c,a,r]).
noun([p,l,a,n,e]).
verb([f,l,i,e,s]).
verb([d,r,i,v,e,s]).
% - Local version for alternate search rule
append_([],X,X).
append_([X|Y],Z,[X|W]) :- append_(Y,Z,W). ?- myphrase([t,h,e,' ',p,l,a,n,e,' ',f,l,i,e,s]).
?- myphrase([t,h,e,' ',p,l,a,n,e]).
?- myphrase(X).
?- myphrase(X).We get fair generation!
:- module(_,_).
% :- use_package(sr/bfall).
myphrase(P,C) :-
% Article is beginning of phrase, rest is beginning of spaces
article(P,CA), spaces(CA,CS1),
noun(CS1,CN), spaces(CN,CS2),
verb(CS2,C).
article([a|T],T).
article([t,h,e|T],T).
spaces([' ' | T],T).
spaces([' ' | Y],T) :-
spaces(Y,T).
noun([c,a,r | T],T).
noun([p,l,a,n,e | T],T).
verb([f,l,i,e,s | T],T).
verb([d,r,i,v,e,s | T],T).?- myphrase([t,h,e,' ',p,l,a,n,e,' ',f,l,i,e,s|T], T).
?- myphrase([t,h,e,' ',p,l,a,n,e|T], T).
?- myphrase([t,h,e,' ',p,l,a,n,e,' ',f,l,i,e,s], []).
?- myphrase([t,h,e,' ',p,l,a,n,e], []).
?- myphrase(X, T).
?- myphrase(X, []).
?- myphrase(X, []).
:- module(_,_).
% :- use_package(sr/bfall).
myphrase(P,C) :-
article(P,CA), spaces(CA,CS1),
noun(CS1,CN), spaces(CN,CS2),
verb(CS2,C). article( "a" || T, T). % Translates to article( [ 97|T], T). % i.e., article( [0'a|T], T). article( "the" || T, T). % Translates to article( [0't,0'h,0'e|T], T). spaces( " " || T, T). spaces( " " || Y, T) :- spaces(Y, T). noun( "car" || T, T). noun( "plane" || T, T). verb( "flies" || T, T). verb( "drives" || T, T).
?- myphrase("the plane flies", []).?- myphrase("the plane", []).?- myphrase(S, []).
?- set_prolog_flag(write_strings, on).
?- myphrase(S, []).
?- myphrase(S, []).
:- module(_,_). :- use_package(dcg). % :- use_package(sr/bfall). myphrase --> article, spaces, noun, spaces, verb. article --> "a". article --> "the". spaces --> " ". spaces --> " ", spaces. noun --> "car". noun --> "plane". verb --> "flies". verb --> "drives".
?- set_prolog_flag(write_strings, on).
?- myphrase("the plane flies", []). ?- phrase(myphrase,"the plane flies").
?- myphrase("the plane", []).?- myphrase(S, []).
?- myphrase(S,[]).
:- module(_,_). :- use_package(dcg). % :- use_package(sr/bfall). myphrase --> article, spaces, noun, spaces, verb. % Translates to: % myphrase(X,C) :- article(X,CA), spaces(CA,CS1), noun(CS1,CN), % spaces(CN,CS2), verb(CS2,C). article --> "a". % Translates to (*): article( "a" || X, X). article --> "the". spaces --> " ". spaces --> " ", spaces. noun --> "car". noun --> "plane". verb --> "flies". verb --> "drives".
?- set_prolog_flag(write_strings, on).
?- myphrase("the plane flies", []). ?- phrase(myphrase,"the plane flies").
?- myphrase("the plane", []).?- myphrase(S, []).
?- myphrase(S,[]).
:- module(_,_).
:- use_package(dcg).
% :- use_package(sr/bfall).
myphrase(N) --> article(AC), spaces(S1), noun(NC), spaces(S2),
verb(VC), { N is AC + S1 + NC + S2 + VC }.
% Translates to:
% myphrase(N,X1,X6) :- article(AC,X1,X2), spaces(S1,X2,X3), noun(NC,X3,X4),
% spaces(S2,X4,X5), verb(VC,X5,X6), N is AC+S1+NC+S2+VC.
article(1) --> "a".
article(3) --> "the".
spaces(1) --> " ".
spaces(N) --> " ", spaces(N1), { N is N1+1 }.
noun(3) --> "car".
noun(5) --> "plane".
verb(5) --> "flies".
verb(6) --> "drives". ?- set_prolog_flag(write_strings,on).
?- myphrase(NChars, "the plane flies", []).Or, using the phrase/2 built-in:
?- phrase(myphrase(NChars), "the plane flies").
?- myphrase(NChars, "the plane", []).
?- myphrase(NChars, S, []).Try also uncommenting the :- use_package(sr/bfall). above, reloading, and, again:
?- myphrase(NChars,S,[]).
Do some exercises on grammars: exercise! ▶
main(_) :- repeat, read(X), process(X). process(end). process(X) :- display(X), nl, fail.
| Arrays | Assoc | Attributes | Heaps |
|---|---|---|---|
| Lists | Term Utilities | Ordset | Queues |
| Random | System Utilities | Tree | UGraphs |
| WGraphs | Sockets | Linda/Distribution | Persistent DB |
| CLPB | CLPQR | CLPFD | Objects |
| GCLA | TclTk | Tracing | Chars I/O |
| Runtime Utilities | Timeout | Xrefs | WWW |
| Java Interface | ... | ... | ... |