酷兔英语

章节正文

relations and functions in mathematics and in Prolog

(If you are looking for the Prolog implementation of mathematical functions like sin, cos, sqrt, log, exp, etc., look under built-in functions.)
A binary relation, in mathematics, is a set of ordered pairs. For example, if we are thinking about the 3 animals: mouse, rabbit, and sheep, and the "smaller" relation, then the set of pairs would be {(mouse, rabbit), (mouse, sheep), (rabbit, sheep)}. In mathematical notation, you would write, e.g., (mouse, rabbit) ∈ smaller, or mouse smaller rabbit. Or you might use a symbol instead of smaller, perhaps "<" - mouse < rabbit, or σ - mouse σ rabbit. This is referred to as an infix notation, because the name of the relation is written in-between the two objects (mouse and rabbit).

 

In Prolog, instead, by default we use prefix notation: smaller(mouse, rabbit). See op if you want to define an infix operator in a Prolog program.

This view of a relation is sometimes called the extensional view - you can lay out the full "extent" of the relation, at least in the case of a relation over a finite number of items, like our "smaller" example. The alternative view is called intensional, where we focus on the meaning of the relation. In Prolog, this corresponds to a rule expressing the relation, such as:

smaller(X, Y) :-
    volume(X, XVolume),
    volume(Y, YVolume),
    XVolume < YVolume.

This, of course, only defines a meaning or intension for smallerrelative to the unspecified meaning of the relation volume(_,_), and the meaning of <, which is defined by the Prolog implementation.

 

When we come to non-binary relations, such as unary ones (like is_a_dog(fido)) or ternary ones (like gives(john, mary, book) or between(rock, john, hard_place)) the infix relation doesn't make any sense, so prefix notation is normal. (Postfix notation - fido is_a_dog can work for unary relations.)

While we often don't think of it this way, a function is a kind of relation. If you are thinking about the functionf(x) = x2, then the essential thing is that for each value of x, there is a value of f(x) (namely x2). In fact, there is a unique value of f(x). So a function (of a single variable) can be viewed as a binary relation such that for every relevant first componentx, there is exactly one pair in the relation that has that first component*: the pair is (x, f(x)). In the case of f(x) = x2, the pairs are (x, x2) for every applicable value of x. We need to specify what the applicable values of x are - the domain of the function. If the domain is {1, 2, 3}, then the pairs are {(1,1), (2,4), (3,9)}. If the domain is all natural numbers, then we can't write out the extension of the function in full, but we can use a set expression such as {(n, n×n) | nN} where N signifies the set of all natural numbers.

In Prolog, despite the fact that it uses a relational notation (except for arithmetic expressions), functions are common, but expressed using the relational notation that depends on the definition/convention in the previous paragraph. In our Prolog code defining smaller(X, Y), above, the relation called volume is in fact a function written relationally. We are saying that for every relevant object X there is a value XVolume that is the volume of X. This is a function-type relationship.

The notion of domain applies to relations as well as functions: a more detailed definition of a binary relation on a set A says that such a relation is a subset of the set A×A of all pairs of elements of A. A is the domain of the relation. A binary relation between sets A and B is a subset of A×B. And so on for ternary relations and beyond. A unary relation on A is just a subset of A. Thus is_a_dog is a subset of the set of all Animals. Or a subset of the set of all Things, depending on just how broadly you want to consider the concept of being a dog.

However, in Prolog, domains of relations are not explicitly addressed.# The notion of domain corresponds exactly to that of type in typed programming languages like, C, C++, Java, Haskell, etc. Prolog has no built-in way of confining the definition of a relation (whether extensionally or by a rule) to a particular domain. If you want to, you can build type-checking into your rules, e.g. by giving an definition of a type as a unary relation. For example, if you wanted to define the type of all popes, you could enumerate them all, though the list would be long:

pope(peter).
...
pope(john_paul_ii).
pope(benedict_xvi).

Then the goal pope(X) would check if X was/is a pope.

 

Another example: when defining the relation sister in Prolog, you would usually write something like:

sister(Person1, Person2) :-
    female(Person1), female(Person2),
    mother(Person1, Mother), mother(Person2, Mother),
    father(Person1, Father), father(Person2, Father),
    Person1 == Person2.

female(Person1) and female(Person2) are type-checks - without them, you are defining sibling, not sister. In practice, you can't enumerate all females, unlike all popes, but in many cases you would be able to enumerate all the relevant ones.

 

In some cases, you might be able to write rules to do type-checking. Prolog includes some built-in predicates for type-checking: number(X) succeeds if X is a number, while integer(X) succeeds only if X is a an integral (whole) number. Here is a rule to check if a number is divisible by 3.

div_by_3(X) :-
    X mod 3 =:= 0.

There is no special syntax for creating functions in Prolog (though there are special arrangements for built-in mathematical functions). To create a function in Prolog, you have to use the relation syntax and create a "relation that happens to be a function". You can do this extensionally, as in

beats(rock, scissors).
beats(paper, rock).
beats(scissors, paper).

or intensionally, with a rule, as with the functionf(x) = x2, which could be coded in Prolog like this (using the name square_of):

square_of(X, XSquared) :-
  number(X),
  XSquared is X * X.

used as in the next examples:

?- square_of(3.2, Y).
Y = 10.24

The number(X) test implicitly limits the domain of the function to numbers.

 

Note that while we defined square_of with a functional usage in mind, it can still be used in a relational sense if desired:

?- square_of(3, 9).
true.

 

Footnotes:
* if there is, not exactly, but at most one pair in the relation that has x as its first member, we say that the relation is a partial function. A partialfunction is like a function that has "holes" in it - f(x) never has more than one value, but for some x in the domain of the function, f(x) might not have any value. A real-life example is the partialfunctioneldest_child_of, defined on the domain of all adult humans.

# there are a couple of areas of Prolog where there is some built-in type-checking - for example, the built-in predicate < will generate an error message if you try to use it compare a string like 'mouse' with a number like 9.

 

repeat

The built-in predicate repeat behaves as if defined by:

 

repeat.
repeat :- repeat.

Thus repeat succeeds when first called, thanks to the first clause. If the Prolog interpretersubsequently backtracks, the second clause (repeat :- repeat.) is tried. This initiates a new call to repeat, which succeeds via the first clause, and so on.

For a practical example of a use of repeat, see here.

 

retract, retractall

retract is a built-in meta-predicate used to remove facts or rules from the Prolog database while a program is executing. It is most often used in partnership with assert (or one of its relatives). For example, your program might have hypothesised that some fact or rule is correct, added it to the Prolog database using assert (or one of its relatives), then your program explores the consequences of that assumption, and concludes that the fact or rule was wrong. So then the programretracts the fact or rule.

 

More prosaically, you might simply have a query that runs repeatedly during a single prolog session, discovers some new facts in each run, but needs to get rid of them at the start of the next query. So again, retract can be used to clean the discovered facts out of the database.

?- assert(likes(mary, pizza)).
true.
?- likes(mary, pizza).
true.
?- retract(likes(mary, pizza)).
true.
?- likes(mary, pizza).
false.
?- assert((happy(X) :- rich(X), famous(X))).
X = _G180
true.
?- retract((happy(X) :- rich(X), famous(X))).
X = _G180
true.

Don't worry about the X = _G180, that's just SWI Prolog renaming the variableX with a unique name so it doesn't get confused with the (different) variableX that you might have used in some other rule. Note also the extra pair of parentheses () around the rule, as opposed to the fact.

What a call to retractactually does is to remove the first fact or rule that matches the argument to retract. If you want to remove, say, all the facts relating to likes with two arguments, it looks as though you might have to call retract repeatedly. Never fear, retractall is here! This meta-predicate, as its name suggests, retracts all facts or rules that match its single argument. For example:

?- assert(likes(mary, pizza)), assert(likes(john, beer)).
true.
?- listing(likes).
:- dynamic likes/2.
likes(mary, pizza).
likes(john, beer).

The ":- dynamic/2" tells us that likes/2 is a built-in predicate that can be modified during programexecution (see dynamic). This is to stop the program modifying unauthorised parts of itself, and becoming totally un-debuggable. Example continues:

?- retractall(likes(X, Y)).
X = _G180
Y = _G181 
?- listing(likes).
:- dynamic likes/2.
true.

See also assert. Programs that use retract and retractall may be particularly difficult to debug.

Tip: In some versions of Prolog, retractall may fail if there is nothing to retract. This may seem reasonable (though it is probably a bug in the particular implementation) but can get in the way of a "prophylactic" retractall call to make sure there are no left-over facts/rules lying around from earlier computations. To get around this, assert a dummy fact of the right type (something assert(likes(dummy, dummy)), assuming likes/2 is what you are trying to get rid of), before you call retractall. SWI Prolog does in fact succeed on a retractall call with no matching facts/rules. 



文章标签:词典  

章节正文