Prolog(Programming in Logic的缩写)是一种逻辑编程语言。它建立在逻辑学的理论基础之上, 最初被运用于自然语言等研究领域。
append
The built-in predicate append(?List1, ?List2, ?List1_then_List2)
succeeds if List1
followed by List2 = List1_then_List2
. Examples:
?- append([a, b], [c, d, e], Result). Result = [a, b, c, d, e]. true. ?- append([a, b], SecondBit, [a, b, c, d, e]). SecondBit = [c, d, e] true. ?- append(FirstBit, [c, d, e], [a, b, c, d, e]). FirstBit = [a, b] true.
A not uncommon beginner's mistake is to use append([Head], Tail, List)
to build a list instead of something like List = [Head | Tail]
. This will work, but is like using a bulldozer to dig a hole to plant out a seedling.
Note: there is also an unrelated version of append
that takes a single parameter. This is described under files, and is referred to as append/1
- i.e. 1 argument, while the append
in this article is referred to as append/3
- 3 arguments.
arg
Not a cry of frustration at yet another error message, but rather, an abbreviation for argument, and also the name of a built-in metalogical predicate, that extracts arguments from a structure. Example:
?- arg(2, buys(john, beer), Arg). Arg = beer
It is also possible to put arguments into terms using arg
, should this prove useful:
?- X = likes(mary, Y), arg(2, X, pizza). X = likes(mary, pizza) Y = pizza
argument
See arg
, term.
arithmetic
Many of the usual arithmetic operators are available in Prolog:
Operator | Meaning | Example |
+ | addition | 2 is 1 + 1. |
– | subtraction | 1 is 2 – 1. |
– | unary minus | Try the query X is 1, Y is - X. |
* | multiplication | 4 is 2 * 2. |
/ | division | 2 is 6 / 3. |
// | integer division | 1 is 7 // 4. |
mod | integer remainder | 3 is 7 mod 4. |
** | exponentiation | 1.21 is 1.1 ** 2. |
Except in the context of an arithmeticcomparison operator, arithmetic expressions need to be explicitly evaluated in Prolog, using the is
built-in predicate.
Mostly one uses these operators in a goal more like this:
X is Y + 2
where Y
is a variable already bound to a numeric value, or perhaps a arithmeticcomparison goal like this:
X > Y * Z
Here's another example: a rule to tell if a (whole) number is odd:
odd(Num) :- 1 is Num mod 2.
Another way to do this one is to use =:=
:
odd(Num) :- Num mod 2 =:= 1.
If you wanted to be more cautious, you could first check that Num
is in fact a whole number:
odd(Num) :- integer(Num), 1 is Num mod 2.
As usual in digital computations, with fractional numbers, it is necessary to be careful with approximation issues. Thus the final example in the table above, 1.21 is 1.1 ** 2.
actually fails when typed into Prolog as a query. This is because 1.1 ** 2, as represented in computers, actually comes out to be something like 1.210000000001. See the section on comparison operators for a solution to this issue.
Note that SWI Prolog does some apparently strange stuff in the domain of arithmetic (dialogue below done with SWI-Prolog Version 5.6.58):
?- X is [a]. X = 97. ?- X is [a] + [b]. X = 195. ?- X is sqrt(23456). X = 153.154. ?- X is sqrt([23456]). X = 153.154. ?- X is sqrt(123456789). X = 11111.1. ?- X is sqrt([123456789]). X = 13.3791.
The ASCII code for a is 97, which sort of explains the first two query outcomes. The last pair of queries are particularly strange. It is best to avoid relying on this sort of thing, and stick to standard arithmetical notation. Avoid strange tricks: code should be comprehensible.
See also comparison operators, built-in functions.
arity
The arity of a functor is the number of arguments it takes. For example, the arity of likes
, as in likes(jane, pizza)
, is 2, as it takes two arguments, jane
and pizza
.
Arity Example Could Mean ... 0 linux.
a bit like #define LINUX
in* C1 happy(fido).
Fido is happy. 2 likes(jane, pizza).
3 gave(mary, john, book).
Mary gave John a book.
* hard to use in practice in Prolog: if the code contains linux.
then you could test for this, but if it doesn't, then testing linux
in your code will trigger an "Undefined procedure: linux/0" error. You can work around this by declaring linux
to be dynamic - i.e. putting the line
:- dynamic linux/0.
in your code (usually at the start).
Every fact and rule in a Prolog program, and every built-in predicate has an arity. Often this is referred to in descriptions of these facts and rules, by appending /
and the arity to the name of the rule or fact. For example, the built-in predicate member/2 has arity 2.
A fact or rule can have more than one arity. For example, you might want to have two versions of make
terms:
% make(X, Y, Z): X makes Y for Z make(fred, chest_of_drawers, paul). make(ken, folding_bicycle, graham). % make(X, Y): X makes Y make(steve, fortune). make(kevin, mistake).
What we have here are make/3
and make/2
.
assert
, asserta
, assertz
assert is a meta-predicate that adds its single argument, which may be a fact or a rule, to the Prolog database. The idea is that you construct or learn a new fact or rule in the course of executing your Prolog program, and you want to add it to the database. asserta
ensures that the added fact/rule is added before any other facts or rules with the same functor), while assertz
adds the fact after any other rules or facts with the same functor. When more than one rule/fact with the same functor is present in the database, they are tried in the order that they appear in the database, hence the need for asserta
and assertz
. You would use asserta
in the common case where the new fact is supposed to save the effort involved in checking the fact using rules and other facts. You might use assertz
, for example, if you were trying to construct a queue data structure (where items are added to the end of the queue. Examples:
?- assert(rich(mary)). true. ?- rich(mary). true. ?- assert((happy(X) :- rich(X), healthy(X))). X = _G180 ?- assert(healthy(mary)). true. ?- happy(X). X = mary
Facts/rules that are loaded from a file cannot be mixed with facts/rules that are created using assert
/asserta
/assertz
without take the special step of declaring the procedure in question to be dynamic. For example, if you have a rule to say, computeN!, with header factorial(+N, -Result)
, i.e with functor factorial
and arity 2, and you also want to use asserta
to add pre-computed values of some factorials to the Prolog database (see also memoisation), then you need to declare factorial
to be dynamic, by including the following with your loaded rules for factorial
:
:- dynamic factorial/2.
Programs with assert
ed facts and rules can be extra hard to debug.
See also retract
, retractall
, dynamic
.
atom
An atom, in Prolog, means a single data item. It may be of one of four types:
likes
, john
, and pizza
, in likes(john, pizza).
Atoms of this type must start with a lower case letter. They can include digits (after the initial lower-case letter) and the underscore character (_
).[]
. This is a strange one: other lists are not atoms. If you think of an atom as something that is not divisible into parts (the original meaning of the word atom, though subverted by subatomic physics) then []
being an atom is less surprsing, since it is certainly not divisible into parts.<--->
, ...
, ===>
. When using atoms of this type, some care is needed to avoid using strings of special characters with a predefined meaning, like the neck symbol:-
, the cut symbol!
, and various arithmetic and comparison operators.+
, -
, *
, /
, <
, >
, =
, :
, .
, &
, _
, and ~
.
Numbers, in Prolog, are not considered to be atoms.
atom
is also the name of a built-in predicate that tests whether its single argument is an atom.
?- atom(pizza). true. ?- atom(likes(mary, pizza)). false. ?- atom(<-->). true. ?- atom(235). false. ?- X = some_atom, atom(X). X = some_atom.
The final example means that atom(X)
has succeeded, with X
bound to some_atom
.
atom_chars
The built-in Prolog predicate atom_chars
can convert an atom into the list of its constituent letters, or vice-versa. A fairly broad concept of atom is used: this predicate will glue together (or split up) any reasonable characters you give it. A possible list would be to put together a list of letters read, one character at a time, to make a word - that is, an atom whose name is the word. Examples:
?- atom_chars(pizza, List). List = [p, i, z, z, a] ?- atom_chars(Atom, [b, e, e, r]). Atom = beer ?- atom_chars(2007, List). List = ['2', '0', '0', '7'] ?- atom_chars(Atom, ['[', '3', ' ', ',', '4', ']']). Atom = '[3 ,4]'
See also atom_codes
.
atom_codes
The built-in Prolog predicate atom_codes
can convert an atom into the list of the numeric codes used internally to represent the characters in the atom, or vice-versa. Examples:
?- atom_codes(pizza, List). List = [112, 105, 122, 122, 97] ?- atom_codes(Atom, [98, 101, 101, 114]). Atom = beer
See also atom_chars
.