Prolog:
facts, rules, queries (like SQL)
capitalization: word begin with lowercase character --> atom (fixed value) ; begin with uppercase letter or underscore --> variable
(swi-prolog in cygwin: open the interpreter with "swipl")
(each line end with ".")
"\+" does logical negation, so \+(X = Y) means X is not equal to Y
a fact, e.g.
likes(wallace, cheese).
a rule, e.g. (a rule with 2 parameters, 3 variables, and 3 subgoals)
friend(X, Y) :- \+(X = Y), likes (X, Z), likes(Y, Z).
load a file and compile,
?- ['friends.pl'].
query
flavor(sweet, What).
when typed the ";", prolog find another one
prolog is not procedural (we have no algorithm), but a declarative language. prolog is not about writing algorithms to solve logical problems. prolog is about describing your world as it is and presenting logical problems that your computer can try to solve.
"unification" means "find the values that make both sides match". "=" means unify, or make both sides the same.
in general, if you can describe the problem, you have solved the problem. you don't have to describe the solution to a problem. you have only to describe the problem.
queries: two forms: 1. the query specifies a fact, and prolog tells yes or no; 2. query with variables, and prolog compute all possibilities that make the facts true.
tail recursion optimization: if position the recursive subgoal at the end of a recursive rule, prolog can optimize the call to discard the call stack, keeping memory constant.
ancestor(X, Y) :- father(X, Y).
ancestor(X, Y) :- father(X, Z), ancestor(Z, Y).
list and tuple:
?- [a, b, c] = [Head|Tail].
Head = a
Tail = [b,c]
[Head|Tail] won’t unify with an empty list, but a one-element list is fine. for example, grab the third element:
?- [a, b, c, d, e] = [_, _|[Head|_]].
Head = c
_ is a wildcard and unifies with anything.
math:
count(0, []).
count(Count, [Head|Tail]) :- count(TailCount, Tail), Count is TailCount + 1.
sum(0, []).
sum(Total, [Head|Tail]) :- sum(Sum, Tail), Total is Head + Sum.
average(Average, List) :- sum(Sum, List), count(Count, List), Average is Sum/Count.
list append, concatenate:
concatenate([], List, List).
concatenate([Head|Tail1], List, [Head|Tail2]) :- concatenate(Tail1, List, Tail2).
thus, rules applied in both directions of :-
GNU Prolog has a built-in predicate to express possible values, called fd_domain(List, LowerBound, UpperBound) . We’ll use a GNU Prolog predicate to test for repeated elements. fd_all_different(List) succeeds if all the elements in List are different.
4x4 Sudoku:
valid([]).
valid([Head|Tail]) :-
fd_all_different(Head),
valid(Tail).
sudoku(Puzzle, Solution) :-
Solution = Puzzle,
Puzzle = [S11, S12, S13, S14,
S21, S22, S23, S24,
S31, S32, S33, S34,
S41, S42, S43, S44],
fd_domain(Solution, 1, 4),
Row1 = [S11, S12, S13, S14],
Row2 = [S21, S22, S23, S24],
Row3 = [S31, S32, S33, S34],
Row4 = [S41, S42, S43, S44],
Col1 = [S11, S21, S31, S41],
Col2 = [S12, S22, S32, S42],
Col3 = [S13, S23, S33, S43],
Col4 = [S14, S24, S34, S44],
Square1 = [S11, S12, S21, S22],
Square2 = [S13, S14, S23, S24],
Square3 = [S31, S32, S41, S42],
Square4 = [S33, S34, S43, S44],
valid([Row1, Row2, Row3, Row4,
Col1, Col2, Col3, Col4,
Square1, Square2, Square3, Square4]).
Eight-Queens:
valid_queen((Row, Col)) :-
Range = [1,2,3,4,5,6,7,8],
member(Row, Range), member(Col, Range).
valid_board([]).
valid_board([Head|Tail]) :- valid_queen(Head), valid_board(Tail).
rows([], []).
rows([(Row, _)|QueensTail], [Row|RowsTail]) :-
rows(QueensTail, RowsTail).
cols([], []).
cols([(_, Col)|QueensTail], [Col|ColsTail]) :-
cols(QueensTail, ColsTail).
diags1([], []).
diags1([(Row, Col)|QueensTail], [Diagonal|DiagonalsTail]) :-
Diagonal is Col - Row,
diags1(QueensTail, DiagonalsTail).
diags2([], []).
diags2([(Row, Col)|QueensTail], [Diagonal|DiagonalsTail]) :-
Diagonal is Col + Row,
diags2(QueensTail, DiagonalsTail).
eight_queens(Board) :-
length(Board, 8),
valid_board(Board),
rows(Board, Rows),
cols(Board, Cols),
diags1(Board, Diags1),
diags2(Board, Diags2),
fd_all_different(Rows),
fd_all_different(Cols),
fd_all_different(Diags1),
fd_all_different(Diags2).
an optimized 8-queen program:
valid_queen((Row, Col)) :- member(Col, [1,2,3,4,5,6,7,8]).
valid_board([]).
valid_board([Head|Tail]) :- valid_queen(Head), valid_board(Tail).
cols([], []).
cols([(_, Col)|QueensTail], [Col|ColsTail]) :-
cols(QueensTail, ColsTail).
diags1([], []).
diags1([(Row, Col)|QueensTail], [Diagonal|DiagonalsTail]) :-
Diagonal is Col - Row,
diags1(QueensTail, DiagonalsTail).
diags2([], []).
diags2([(Row, Col)|QueensTail], [Diagonal|DiagonalsTail]) :-
Diagonal is Col + Row,
diags2(QueensTail, DiagonalsTail).
eight_queens(Board) :-
Board = [(1, _), (2, _), (3, _), (4, _), (5, _), (6, _), (7, _), (8, _)],
valid_board(Board),
cols(Board, Cols),
diags1(Board, Diags1),
diags2(Board, Diags2),
fd_all_different(Cols),
fd_all_different(Diags1),
fd_all_different(Diags2).
prolog programming: step 1, build a knowledge base; step 2, compile the knowledge base and ask questions
rather than simple assignment, prolog uses a process called unification that makes variables on both sides of a system match.
Prolog Tutorials:
http://en.wikipedia.org/wiki/Prolog
http://www.csupomona.edu/~jrfisher/www/prolog_tutorial/contents.html
http://www.lix.polytechnique.fr/~liberti/public/computing/prog/prolog/prolog-tutorial.html
http://kti.mff.cuni.cz/~bartak/prolog/contents.html