Title: Writing and debugging programs
1Writing and debugging programs
- Programs should be designed top-down and built
bottom-up. Style and presentation are aids to
producing correct programs. Once written,
programs should be tested analytically.
2This lecture is about
- designing programs top-down
- building the code for a program bottom-up
- using a good style to make programs more easily
understood - testing programs systematically and analytically
so you can be as certain as possible each part
works as intended.
3Designing programs - 1
Write a program that separates a list of letters
into a list of vowels and a list of non-vowels.
It might be run as follows ?-
classify(a,b,c, Vowels,NonVowels). Vowels
a, Non_Vowels b,c ? no
4Designing programs - 2
This is a list processing problem.
It is a terminate at the end of list problem.
We need to be able to distinguish between vowels
and consonants.
5Designing programs - 3
- There are three conditions and actions
- the list of letters is empty terminate
- the head of the list is a vowel add to the list
of vowels and process the tail - the head of the list is not a vowel add to the
list of consonants and process the tail.
6Designing programs - 4
- We have to decide what arguments we need to pass
in and out of the procedure - list of letters input
- list of vowels found output
- list of consonants found output.
7Detailed design - 1
- As this is a simple problem, we can quickly move
to turning our thoughts into code
the list of letters is empty terminate In this
problem, we can say that when there are no
letters, then there are no vowels or consonants
1 terminating classify(, , ).
8Detailed design - 2
- Having coded the terminating condition, we can
move to the recursive clauses
the head of the list is a vowel add to the list
of vowels and process the tail 2 - recursive
letter is a vowel classify(VowelTail,VowelVow
el_Tail, Non_Vls) -
vowel(Vowel), classify(Tail, Vowel_Tail,
Non_Vls).
9Detailed design - 3
- We can process vowels, so we need to be able to
process consonants
the head of the list is not a vowel add to the
list of consonants and process the tail 3 -
recursive letter is not a vowel classify(Non_Vow
elTail, Vowels, Non_VowelNon_Vl_Tai
l) - classify(Tail, Vowels, Non_Vl_Tail).
10Detailed design - 4
- We are left with one piece of code to be written
vowel/1.
vowel(a). vowel(e). vowel(i). vowel(o). vowel(u).
11Building the program
- By the end of detailed design, the program will
be just about complete. - The next stage is to type the program into an
editor and test that it works one procedure at
a time. -
- The first procedure to be tested is the deepest
in this case vowel/1.
12The importance of layout - 1
- Layout is a quick guide to the structure of your
program. - Until you are an expert Prolog programmer, follow
the usual conventions. - Facts always against the left-hand margin, eg
- member(Elem, Elem_Tail).
13The importance of layout - 2
- Rules should usually contain no more than 10
subgoals 4-5 is more common. - The head is always set against the left-hand
margin. - Subgoals indented by 5 spaces
- goal_head(Arg1, Arg2) -
- subgoal1(Arg1, Via),
- subgoal2(Via, Arg2).
14Comments - 1
- Prolog has two kinds of comments
- / This starts a comment that can go on for many
lines until it reaches / - starts an in-line comment
15Comments - 2
- It is conventional to include a block comment for
each procedure that includes - / /
- / functor/arity /
- / details of each argument /
- / summary of what the procedure does /
- / author /
- / date /
- / /
16Testing a program - 1
- Try to test individual clauses in a procedure
then test the whole procedure. - vowel/1 is quite easy to test
?- vowel(Letter). Letter a ? Letter e ?
Letter i ? Letter o ? Letter u ? no
17Testing a program - 2
- Test the terminating clause(s) of procedures that
use recursion.
?- classify(, Vowels, Non_Vowels). Vowels
, Non_Vowels ? no
18Testing a program - 3
- Test the recursive clauses of procedures that use
recursion one-by-one.
?- classify(b,c,d,Vowels,Non_Vls). Vowels
, Non_Vls b,c,d ? no
19Testing a program - 4
- Test the recursive clauses of procedures that use
recursion one-by-one.
?- classify(a,e,i,o,Vowels,Non_Vls).
Vowels
a,e,i,o, Non_Vls ? Vowels
a,e,i, Non_Vls o ? no
20Testing a program - 4
- Clearly something is wrong.
- Consonants are processed OK but vowels arent.
- Perhaps vowels are also being processed by the
consonants rule?
21Testing a program - 5
- We can test this easily by adding a write/1
subgoal to the rule - 3 - recursive letter is not a vowel
- classify(Non_VlTail, Vowels,
- Non_VlNon_Vl_Tail) -
- write(Non_Vl), nl,
- classify(Tail, Vowels, Non_Vl_Tail).
22Testing a program - 6
- When this is run, we get
- ?- classify(a,e,i,o,u, Vowels,
- Non_Vls).
Vowels a,e,i,o,u, - Non_Vls ?
- u
- Vowels a,e,i,o,
- Non_Vls u ?
23Testing a program - 7
- So, we need to stop both recursive clauses
working - 3 - recursive letter is not a vowel
- classify(Non_VowelTail, Vowels,
- Non_VowelNon_Vl_Tail) -
- \ vowel(Non_Vowel),
- classify(Tail, Vowels, Non_Vl_Tail).
24Three useful things Singleton variables
- Look at the error messages when consulting a
program - member(Head, Heda_).
- Head,Heda - singleton variables in
usermember/2 Approximate lines 22-26, -
25Three useful things trace/notrace
- Prolog includes some debugging goals.
- To see what is happening in detail, use
trace/notrace. - 2 - recursive letter is a vowel
- classify(VowelTail, VowelTail,
- Non_Vls) -
- trace,
- vowel(Vowel),
- notrace,
- classify(Tail, Vl_Tail, Non_Vls).
26Three useful things write/nl
- You can also add write/1 subgoals into rules to
see what is going on, eg - 2 - recursive letter is a vowel
- classify(VowelTail, VowelVl_Tail,
- Non_Vls) -
- vowel(Vowel),
- write(classify(Tail, Vl_Tail, Non_Vls)),
- nl,
- classify(Tail, Vl_Tail, Non_Vls).
27Summary
- Programs should
- be designed top-down
- be built bottom-up
- tested procedure-by-procedure.
- There are a few other general techniques
- singleton variables
- trace/notrace
- writing subgoals.