In formulating these layout rules, we have taken certain arbitrary choices between different sensible formatting variants. While these choices work well for us, you may want to adapt a slightly different style. As long as it is done consistently (and agreed within a team), you should follow your own preferences.
Code should be indented consistently. Tabs should be every 8 spaces. Indentation should be one tab per level of indentation, except for highly indented code which may be indented at 4 spaces per level of indentation after the first.
Each line should not extend beyond 79 characters, unless this is necessary due to the use of long string literals. If a statement or predicate call is too long, continue it on the next line indented two levels deeper. If the statement or call extends over more than two lines, then make sure the subsequent lines are indented to the same depth as the second line. For example:
Here is A_really_long_statement_that_does_not_fit + On_one_line + In_fact_it_doesnt_even_fit + On_two_lines.
Don’t put more than one statement or call on a line.
Put spaces after commas in comma-separated lists. Put spaces either
side of infix operators. In both cases, this makes them easier to read,
particularly in expressions containing long names or names with underscores.
(There are some exceptions, such as module qualification
foo/3. But not unification
X = Y or list consing
[Head | Tail].)
Make judicious use of single blank lines in clause bodies to separate logical components.
Keep all clauses of a predicate in the one place. Leave at least one blank line between the clauses of one predicate and the next (particularly if they have similar names), since otherwise they may at first glance appear to be all from the same predicate (of course, this never happens because there’s a comment before every predicate, right?). Similarly, it is best not to leave blank lines between the clauses of a predicate (particularly if done inconsistently), since otherwise at first glance they may appear to be from different predicates.
Clause heads should be flush against the left margin. As well as making them easier to pick out visually, this makes it easier to grep for the definitions of predicates (as opposed to their invocations). The head/body separator ‘:-’ should follow the head on the same line. The body of the clause should then commence on the next line, indented one tab stop.
non_overlap(Start1, Dur1, Start2, _Dur2):- Start1 + Dur1 #=< Start2. non_overlap(Start1, _Dur1, Start2, Dur2):- Start1 #>= Start2 + Dur2.
If-then-elses should always be parenthesised. Always include the else part, even if you don’t think it’s required. Always put semicolons at the start of a new line, aligned with the opening and closing parentheses. Example:
( test1 -> goal1 ; goal2 ),
Disjunctions should be formatted in a similar way. Example:
( goal1 ; goal2 ).
Do loops should also always be parenthesised. Loop conditions should be listed one per line, starting after the opening parenthesis and indented one character. The ‘do’ keyword should be at the end of the last condition. The body of the loop should then follow on the next line, again indented. Example:
(for(J, I + 1, N), param(A, I) do Diff is J - I, A[I] #\= A[J], A[I] #\= A[J] + Diff, A[I] #\= A[J] - Diff ).
Every predicate should have a one line comment documenting what it does, all module interfaces should be properly documented with a comment directive.
If an individual clause is long, it should be broken into sections, and each section should have a block comment describing what it does; blank lines should be used to show the separation into sections. Comments should precede the code to which they apply, rather than following it.
% % This is a block comment; it applies to the code in the next % section (up to the next blank line). % blah, blah, blahblah, blah,
If a particular line or two needs explanation, a line comment
% This is a "line" comment; % it applies to the next line or two % of code blahblah
or an inline comment
blahblah % This is an "inline" comment
should be used.