A Prolog predicate consists of multiple clauses. It is useful to think of each clause as coding a separate ``case''--first describe what constitutes the case, then describe the result for that case. For example, the absolute value of a number is (1) the negation of the number, if it is negative, or (2) the number itself, if it isn't negative.
If a case has subcases, feel free to invent another predicate to deal
with the subcases.
abs(X, Y) :- X < 0, Y is -X.
abs(X, X) :- X >= 0.
Remember that parameter transmission is by unification. You can do a lot of your work right in the parameter list. For example:
You can often simplify code by writing parameters that match only the specific case you are interested in. See
second([_, X | _], X). /* 2nd argument is 2nd element of list. */
appendfor examples. (Note: when you must program procedurally, by convention the ``result'' is the last argument.)
Recursion is fully supported. In other languages you must always test
for the base case first; in Prolog, the base case can (and should) go
last, if it is such that the more general clauses will fail--see
append. If the predicate is to fail in the base case, it
can (and should) be omitted; for example, the base case for
member is the unnecessary clause:
You can't keep a value for future use by ``assigning it to a variable.'' If it is temporary, local information, you can pass it around as a parameter; if it is relatively permanent information that should be globally accessible, you can put it in the database (see
member(_, ) :- fail. /* No 1st parameter is a member of  */
retractbelow). Prolog has no functions, so ``results'' must be returned by instantiating one or more parameters.
Many predicates can be used as generators, to generate one solution after another until later conditions are met. For example,
succeeds and instantiates
member(X, [1, 2, 3, 4, 5]), X > 3.
4. If backed into, it re-instantiates
5. (But if you think declaratively, this just says ``
Xis a member of the list
[1, 2, 3, 4, 5]that is greater than
When one clause fails, the next one is tried. If you want the failure of a clause to cause the failure of the entire predicate, you can use a cut-fail combination:
This is a procedural shortcut that avoids the necessity of having
sqrt(X, RootX) :- X < 0, !, fail.(more clauses of sqrt should follow)
X <= 0in every clause; it is justified only if the test is complex and there are many clauses.
Arithmetic is performed only upon request. For example,
2+2=4 will fail, because
4 is a number but
2+2 is a structure with functor '+'. Prolog cannot work
arithmetic backwards; the following definition of square root ought to
work when called with
sqrt(25, R), but it doesn't.
Arithmetic is procedural because Prolog isn't smart enough to solve equations, even simple ones. This is a research area.
sqrt(X, Y) :- X is Y * Y. /* Requires that Y be instantiated. */
It is possible to build a so-called fail loop in Prolog. Such a loop has the form generate-process-test; the loop repeats if the test fails. For example, the following will print the elements of a list, one per line:
However, if the processing is at all complex, it may be difficult to backtrack over it safely. Tail recursion is safer, cleaner, and usually more efficient:
print_elements(List) :- member(Element, List), write(Element), nl, fail.
Both of these fail after printing the list. If this is undesirable (and it probably is), a simple idiom is to add another clause whose purpose is to unconditionally succeed after the first clause is done:
print_elements([Head | Tail]) :- write(Head), nl, print_elements(Tail).