truncate(Exp)
round(Exp)
ceiling(Exp)
These functions should be used in a context where they will actually be evaluated, such as following is
or as part of an arithmeticcomparisonoperator like =:=
or >
.
Example:
?- X is sqrt(2).Compare this with the following, where sqrt(2) is not evaluated, because
X = 1.41421
=
does not evaluate its arguments.?- X = sqrt(2).
X = sqrt(2)
?- X is log(3+2).
X = 1.60944.
These mathematical functions may correspond to arity 2 built-in predicates: for example, one can do this:
?- sqrt(2, X).Some versions of SWI Prolog (e.g. 5.6.47) implement many of these arity 2 predicates, but not e.g.
X = 1.41421
exp/2
.
* High School Maths Reminder Service: if you want the logarithm to base a, divide log(Exp) by log(a). E.g. log10(X) = log(X)/log(10), and log2(X) = log(X)/log(2).
call
is a built-in meta-predicate that allows its single argument to be called/invoked as a goal. For example, a program might create a goal (perhaps using =..
) on the fly, and then, presumably later in the program, need to test the goal. Here are queries that perform these roles - in a real program, both the assert
and the call
would be built in to Prolog procedures written by the programmer.?- assert(likes(mary, pizza)).
?- call(likes(Person, pizza)).
Person = mary
?- Goal =.. [likes, mary, What], call(Goal).
Goal = likes(mary, pizza)
What = pizza
.
"). A clause may be a fact, like:
likes(mary, pizza).
food(pizza).
or a rule, like:
eats(Person, Thing) :- likes(Person, Thing), food(Thing).
A clause may also be a query to the Prolog interpreter, as in:
?- eats(mary, pizza).
A group of clauses about the same relation is termed a procedure.
%
. Comments are ignored by the Prolog interpreter; their purpose is to help a human reader understand the Prolog code. Examples:
% This is a full line comment.
% The next line contains a part-line comment.
member(Item, [Item|Rest]). % member succeeds if Item is 1st object in list.
As in other programming languages, comments should be used freely to explain the high-level significance of sections of code, to explain tricky sections of code, etc. Comments should not echo what the code already clearly says. Comments like that actually get in the way of understanding, for example because they are likely to make the reader ignore the comments. Where it is possible to make code understandable by using a meaningful functor name or variable name, this is preferable to a comment.
It is good practice to begin each Prolog procedure with a comment describing what it does, e.g.
% member(Item, List) - succeeds if the item is a member of the list
If the list needs to have some special properties, e.g. if it must be a list of numbers, or must be instantiated (that is, have a value) at the time the procedure is called, then this headercomment should say so:
% member(Item, List) - succeeds if the item is a member of the list;
% List must be instantiated at the time member is called. Item need not
% be instantiated.
It can be a good idea for the header comments to indicate examples of the kind of data on which the procedure is intended to operate, and what the result should be, if this can be done reasonably briefly. E.g.
% Examples of use:
% ?- member(b, [a, b, c]).
% true.
%
% ?- member(X, [a, b, c]).
% X = a ;
% X = b ;
% X = c ;
% false.
Each file of Prolog code should begin with a (file) header comment, indicating who wrote the code, when, and what it is (overall) intended to do. This would be enough in a short Prolog assignment. In a "industrial strength" Prolog system, there would be details on the origins of algorithms used, and a revision history.
A good source of examples of Prolog commenting is example code made available in class, such as this one. Note however that this one is rather more heavily commented than usual, for instructional purposes. Note also that code examples presented on screen may be under-commented, because of the difficulty of fitting the comments and the code on the screen, and because the oral presentation accompanying the on-screen material replaces the comments to some extent.
Don't make your lines of comments (or code) too long - long lines can be hard to read, and really long lines may be folded, turning your neat formatting into a dog's breakfast. Stick to a maximum line length of 70 or 80 characters. Cute lines and/or boxes constructed of comment characters have the side effect of preventing the reader from seeing as much of your code at one time. The reader may then have to page up and down to figure out what your code does. They will not like you for this.
The use of cuts should normally be commented to explain why the cut is necessary.
It is a bad idea to comment (almost) every line, partly because of the clutter, and the distraction that this causes, and partly because most such comments are pointless duplications of the code (and/or comment things obvious except to a novice Prolog programmer):
Example of bad commenting (every line commented):
factorial(0, 1). % Factorial of 0 is 1.Of these comments, only the first and last are even faintly justifiable, and even these are probably too obvious, as, particularly for the last comment, the variable names tell you everything you need to know. It looks pretty, with all the
factorial(N, FactN) :-
N > 0, % N is positive
Nminus1 is N - 1, % Calculate N minus 1
factorial(Nminus1, FactNminus1), % recursion
FactN is N * FactNminus1. % N! = N * (N - 1)!
%
-signs neatly lined up, but it forces the reader to check through all the unnecessary comments in case there is anything important there. This code needs a procedure header comment, and probably nothing else, though a beginning Prolog programmer might be justified in pointing out that the line N > 0,
is there to make sure that the rule is only used in the case where N
is positive. (If you're not sure why this is so important, try leaving out N > 0,
and test the function on say N = 2
.) So the comment would be "% only use rule if N > 0
."
How to write even worse comments!
It's easy - just write comments that are actually wrong.
Review your comments in a cool moment, and make sure that what they say is true.
The + - ?
convention for arguments to procedures
A convention often used to make the role of arguments to a procedure clearer is to tag them with +
, –
, and ?
, as follows:
Tag | Meaning |
+ | argument is expected to be instantiated (i.e. have a value rather than be a variable) when the procedure is called as a goal. |
– | argument is expected to be a variable to be bound when the procedure is called as a goal. |
? | argument may be either instantiated, or be an unbound variable, when the procedure is called as a goal. |
Example:
% factorial(+N, -FactorialN).It's worth checking out, by the way, what happens if
%% supply a value for N, and FactorialN will be computed.
% member(?Item, ?List).
%% Item and List may either be instantiated, or a variable
%% (but in fact at least one of them must be instantiated!)
List
is not instantiated … ?- member(a, List).and so on … Prolog works its way through all list structures that contain
List = [a|_G231] ;
List = [_G230, a|_G234] ;
List = [_G230, _G233, a|_G237]
a
.
Spelling, grammar, etc.
It's no bad thing if all of these comments are spelled correctly and are grammatically phrased. (Sometimes it is appropriate to abbreviate, so perhaps your comments don't all need to be full sentences.) It makes life harder for folks trying to read your code, if they have to wade through poor spelling and grammar. Remember that the people reading your code will include people you will want to understand your comments easily - helpers, markers, colleagues, your boss, even yourself in a year's time when you've forgotten how you got the code to work … So get into good commenting habits from the start.
See also indentation and white space.