begin every predicate (except auxiliary predicates) with an introductory comment in the standard format. % remove_duplicates(+List, -ProcessedList) % % Removes the duplicates in List, giving ProcessedList
Use descriptive argument names in the introductory comment; they need not to be the same as those in the clauses.
Predicate names
Make all names pronounceable
Never use two different names that are likely to be pronounced alike: if you use foo, do not also use foo_ or fu
Construct predicate names with lower-case, sparating words with underscores: is_well_fomred
Do not mix up to, two, and too
Within names, do not express numbers as words.
Identify auxiliary predicates by appending _aux or _x, _xx and so forth: if you name your main predicate foo and need an auxiliary predicate, then name it foo_aux or foo_x
If a predicate represents a property or relation, its name should be a noun, noun phrase, adjective, prepositional phrase, or indicative verb phrase.
If a predicate is understood procedurally - that is, its job is to do something, rather than to verify a property - its name should be an imperative verb phrase: remove_duplicates
Place arguments in the following order: inputs, intermediate results, and final results.
Consider how your arguments map onto ordinary English: ex. mother_of(A,B) is ambiguous. Naming it mother_child would eliminate the ambiguity.
Variable names
Use descriptive names for variables whereever possible, and make them accurate.
Construct variable names with mixed-case letters, using capitalization to set off words: for ex. write ResultSoFar, not Result_so_far
For variables of purely local significance, use single letters: I, J, K, L, M, N for integers, L, L1,L2,... for lists; A, B, C,..., X, Y, Z for arbitrary terms; H and T for head and tail of a list.
Use a single letter for the first element of a list and a plural name for the remaining elements: for ex. a list of trees: [T|Trees]
Layout
Indent all but the first line of each clause.
If a test is unnecessary because a cut has guaranteeed that it is true, say so in a comment at the appropriate place.
Indent an additional 2 spaces between repeat and the corresponding cut.
Put each subgoal on a separate line, except closely related pairs such as write and nl
Skip a line between clauses, Skip two lines between predicates.
Keep clauses less than 25 lines if possible
Consider redesigning any non_auxiliary predicate that has more than 4 arguments.
Consider using a prettyprinter for finished printouts.
Expresing algorithms
When efficiency is critical, make tests.
Conduct experiments by writing separate small programs, not by mangling the main code.
Use cuts springly but precisely.
Never add a cut to correct an unknown problem
'Avoid the semicolon (;) - make separate clauses instead.
Use parentheses whenever operator precedence is important.
When you sue ; always use parentheses.
Avoid if-then-else structure because that is a rather un-Prolog-like way of thinking.
Avoid append as far as possible
Use difference lists to achieve fast concatenation
Use tail recursion for recursions of unknown depth.
Reliability
Isolate non-portable code.
Isolate "magic numbers": if a number occurs more than once in your program, make it the argument of a fact.
Test code at its bounderies
Test that each loop starts correctly, advances correctly, and ends correctly.
Test every predicate by forcing it to backtrack: for ex. count_up(5), fail.
Test predicates by supplying arguments of the wrong types.
Make error messages informative: Where, What, How
Use the logging library: logging(module,Text,[Variables]).
Add logging(Module,'',[Variables]) for the begin of a prediacte and logging(Module,'',[Variables]) for the end of the predicate.
Mark all temporarily altered lines of code with %TEST
Use write('!!!') to mark places in the program where work remains to be done.