Good vs Bad style of Presenting Prolog Programs
Good vs Bad style of Presenting
Prolog Programs
F. Sadri
1
“Family” Exercise
Emily + John
Ann + Peter Laura + Boris
Ryan + Lucy Gemma
2
Write down facts defining who is
• (1) female
• (2) male and
• (3) who is the child of whom.
Write a predicate that denotes the uncle
relation.
Write a predicate that denotes the aunt
relation.
3
BAD Style answers to the Family-
Exercise
% by StudentFirstName StudentLastName
% Day Month Year
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
female( emily ).
female(gemma).
child(peter, john).
child(laura, emily) .
female(laura ). female(ann).
female(lucy).
4
child(laura,john).
child(ryan, ann).
male(peter).
male(boris ). child( gemma, laura ). male( ryan).
male( john) .
child(peter, emily ).
child(ryan , peter).
child(gemma, boris ).
uncle(X,Y):-child(Y,Z),child(Z,A),
child(X,A),X\=Z,male(X).
aunt(X, W) :-child(W,Z),child(Z,A), child(X,A),
X\=Z,female(X).
5
Good Style answers to the Family-
Exercise
% % with thanks to Claudia Schulz
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
STEP 1
consistent use of whitespaces
all clauses of one predicate together
different predicates are separated by spaces
every clause begins on a new line
STEP 2
comments to explain the predicates and their arguments
predicates have sensible names
document structure
6
Emily + John
Ann + Peter Laura + Boris
Ryan + Lucy Gemma
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% the family database
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% all females – ordered breadth-first
female(emily).
female(ann).
female(laura).
female(lucy).
female(gemma).
% all males – ordered depth-first
male(john).
male(peter).
male(ryan).
male(boris).
7
% is_child_of(Child, Parent) means that Child is the child
% of Parent
% ordered breadth-first
is_child_of(peter, emily).
is_child_of(peter, john).
is_child_of(laura, emily).
is_child_of(laura, john).
is_child_of(ryan, ann).
is_child_of(ryan, peter).
is_child_of(gemma, laura).
is_child_of(gemma, boris).
8
Definition of the uncle and aunt relations:
STEP 3
body of a rule on a new line
every subgoal on a new line with indentation
(e.g. 4 whitespaces)
9
uncle(X,Y):-
is_child_of(Y,Z), A
is_child_of(Z,A),
is_child_of(X,A), Z X
X\=Z,
male(X). Y
aunt(X, W) :-
is_child_of (W,Z),
is_child_of (Z,A),
is_child_of (X,A),
X\=Z,
female(X).
10
STEP 4
use meaningful variable names
e.g. in the uncle rule: Unc (or Uncle or U) instead
of X, Person (or P) instead of Y.
Similarly in the aunt rule: Use Aun (or Aunt or
A).
11
uncle(U,P):-
is_child_of(P,PP), GP
is_child_of(PP,GP),
is_child_of(U,GP), PP U
U\=PP,
male(U). P
aunt(A, P) :-
is_child_of(P,PP),
is_child_of(PP,GP),
is_child_of(A,GP),
A\=PP,
female(A).
12
uncle(U,P):-
is_child_of(P,PP), GP
is_child_of(PP,GP),
is_child_of(U,GP), siblings(PP,U) PP U
U\=PP,
male(U). P
aunt(A, P) :-
is_child_of(P,PP),
is_child_of(PP,GP),
is_child_of(A,GP), siblings(PP,A)
A\=PP,
female(A).
13
STEP 5
define auxiliary predicates:
e.g. siblings (+comments explaining the
predicate)
14
% Child1 and Child2 are siblings if they are
% different children of the same parent.
siblings(Child1, Child2) :-
is_child_of(Child1, Parent),
is_child_of(Child2, Parent),
Child1 \= Child2.
15
uncle(U, P) :-
is_child_of(P, PP),
siblings(U, PP),
male(U).
aunt(A, P) :-
is_child_of(P, PP),
siblings(A, PP),
female(A).
16
Summary: Bad Style
female( emily ).
female(gemma).
child(peter, john).
child(laura, emily) .
female(laura ).female(ann).
female(lucy).
child(laura,john).
child(ryan, ann).
male(peter).
male(boris ).
child( gemma, laura ).
male( ryan).
male( john) .
child(peter, emily ).
child(ryan , peter).
child(gemma, boris ).
uncle(X,Y):-child(Y,Z),child(Z,A),
child(X,A),X\=Z,male(X).
aunt(X, W) :-
child(W,Z),child(Z,A), child(X,A),
X\=Z,female(X).
17
To: Good Style
% all females – ordered breadth-
first
female(emily).
female(ann).
female(laura).
female(lucy).
female(gemma).
% all males – ordered depth-first
male(john).
male(peter).
male(ryan).
male(boris).
\* is_child_of(Child, Parent) means
that Child is the child % of Parent
*/ ordered breadth-first
is_child_of(peter, emily).
is_child_of(peter, john).
is_child_of(laura, emily).
is_child_of(laura, john).
is_child_of(ryan, ann).
is_child_of(ryan, peter).
is_child_of(gemma, laura).
is_child_of(gemma, boris).
18
To: Good Style cntd.
uncle(U, P) :-
is_child_of(P, PP),
siblings(U, PP),
male(U).
aunt(A, P) :-
is_child_of(P, PP),
siblings(A, PP),
female(A).
% Child1 and Child2 are siblings if they are different children of the same parent.
siblings(Child1, Child2) :-
is_child_of(Child1, Parent),
is_child_of(Child2, Parent),
Child1 \= Child2.
19
Prolog – Good Layout Style
Summary
COMMENT your code: header, predicate-description, …
Use whitespaces consistently
Each clause begins in a new line
Rules have the form:
head :-
subgoal1,
subgoal2,
…
last_subgoal.
Indentation: whitespaces
20
Summary cntd.
Predicate-groups: all clauses of one predicate
together
Vertical space between predicate-groups
indicates “distance“
Limit the length of a clause (i.e. the number of
subgoals) by using
auxiliary predicates.
21
• Choose meaningful (& pronouncible?) names for
variables and predicates.
• Prolog-programmers seem to prefer using underscores:
is_uncle_of instead of isUncleOf
• Name of a predicate should indicate the meaning of its
arguments:
mother(X,Y)
mother_of(X,Y)
is_mother_of(X,Y)
mother_child(X,Y)
22
Note that different predicates can have the
same name if their number of arguments are
different:
mother(X,Y)
mother(X,Y,Z)
But it is better if you don’t do this!
23
Argument order:
For example for an accumulator-style predicate
acc(Input,Intermediate,Output)
reverse_list(InputList,IntermediateResult,ReversedList)
Use auxiliary predicates to decrease the number of subgoals in a
clause:
head :-
subgoal1, subgoal2, subgoal3, subgoal4, subgoal5, subgoal6.
Package up some of the subgoals into an auxiliary definition.
This helps readability and re-usability.
24
You have some options, e.g.:
head :-
subgoal1, subgoal2, aux, subgoal6.
aux:-
subgoal3, subgoal4, subgoal5.
Or
head :-
aux1, aux2.
aux1:-
subgoal1, subgoal2, subgoal3.
aux2:-
subgoal4, subgoal5, subgoal6.
You decide which aux definition may be more useful/re-
usable.
25
Tail recursion is efficient, but don’t worry
about it too much.
TEST your program!
Test your program incrementally as you are
developing it.
Trace. / notrace.
Useful for debugging and for understanding the
Prolog query evaluation strategy.
26
Useful Tips and Common Mistakes
The Sicstus Manual:
Http://sicstus.sics.se/documentation.html
Available under “help” when you invoke Sicstus.
“Coding Guidelines for Prolog” by Covington
et al. (2012), Programming, Theory and
Practice of Logic Programming, Volume 12 /
Issue 06 / November 2012, pp 889-927. The
pdf is online.
27
http://sicstus.sics.se/documentation.html
http://sicstus.sics.se/documentation.html
http://sicstus.sics.se/documentation.html
Tips and Common Mistakes:
usage of comma “,”
commas are only used in the body of a rule:
head :- subgoal1, … , last subgoal.
You cannot separate facts by a comma:
Each fact begins on a new line and has a full stop (.)
at the end.
✘ country(britain), country(holland),
country(France).
✔ country(britain).
✔ country(holland).
✔ country(France).
28
You cannot use commas in the head of a rule.
✘ wet(X), cold(X) :- raining, outside(X).
Prolog warning:
!Permission error: cannot redefine built-in ‘,’/2
The head of a rule is always a single atomic
formula.
✔ wet(X) :- raining, outside(X).
✔ cold(X) :- raining, outside(X).
29
Tips and Common Mistakes:
Nesting
Prolog does not allow nesting:
You cannot use
is_mother_of(Mother, Child) :-
is parent_of(female(Mother), Child).
Correct version:
is_mother_of(Mother, Child) :-
is_parent_of(Mother, Child),
female(Mother).
30
Tips and Common Mistakes:
Variables
Remember: Variables start in the upper case and
anything starting with an upper case letter is a variable.
Think carefully before you use variables in the heads of
condition-less clauses!
E.g. If you specify
person(X).
Logically you have specified
X person(X),
and your program will say “yes”, for example to a query
such as
| ?- person(logic_course).
31
Variables are normally used to express
dependencies:
is_mother_of(Mother, Child) :-
is_child_of(Child, Mother),
female(Mother).
If one of the variables doesn’t matter for the
dependencies, you can use an anonymous
variable, i.e. underscore “_“.
If “_” appears multiple times in the same clause,
the occurrences refer to distinct variables.
32
Tips and Common Mistakes:
Singleton Variables
A very common Prolog warning:
[…, …] – singleton variables
Example:
parent(P) :-
is_child_of(Child, P).
[Child] – singleton variables
• This is a warning to help you with two common mistakes:
– Spelling mistakes in variables
– Forgetting to use/bind a variable
• It indicates that there is one or more variable in the clause
that appears only once.
33
Tips and Common Mistakes:
Another Common Warning
Existence error in user: …..
E.g. parent(P) :- child_of(Child, P).
Query: ?- parent(X).
! Existence error in user:child_of/2! procedure
user:child_of/2 does not exist! goal:
user:child_of(_128,_129)
34
Prolog is expecting to find a definition for
child_of/2, but cannot find it.
You may have forgotten to define it, or you may
have defined it but
– you have used a wrong number of arguments, or
– you have a spelling mistake, e.g. childOf or
is_child_of instead of child_of.
35
Tips and Common Mistakes:
Disjunctions
Disjunction has to be used with parentheses:
subgoal1 (subgoal2 subgoal3) becomes
subgoal1, (subgoal2; subgoal3)
Some people also prefer this presentation:
subgoal1,
(subgoal2
; subgoal3
)
36
Tips and Common Mistakes:
is
The “is” predicate:
Used to evaluate arithmetic expressions.
LHS is a variable or a constant, RHS should be
a ground expression when the predicate is
called.
37
Example
| ?- X=5, Y is X+3 ; Y is X+5.
X = 5,
Y = 8 ? ;
! Instantiation error in argument 2 of is/2! goal: _116 is
_119+5
| ?- X=5, (Y is X+3 ; Y is X+5).
X = 5,
Y = 8 ? ;
X = 5,
Y = 10 ? ;
no
38
Tips and Common Mistakes:
Others
Order matters:
In recursive definitions:
– Base case first
– Then the recursive clause
Order of subgoals matters too.
39
Good info about Debugging,
spy, etc
https://sicstus.sics.se/sicstus/docs/3.7.1/html/si
cstus_9.html
40