|
|
|
Logic Programming
In the 1970s a programming language called Prolog was developed.
The semantics of Prolog were derived from logic.
The goal of this lecture is to become familiar with Prolog
to write simple programs.
There is much more to Prolog than we will cover.
Terminology
constant
A constant is an attribute value.
By convention all constants start with lower-case letters.
Some example constants are: joe, cp2001, sue, cp2003, etc.
variable
A variable is like a variable in a mathematical equation, it
represents some constant that has yet to be determined.
For example in the mathematical equation.
X = Y + 3
The variable X is some unknown value, however, we know it is
exactly 3 greater than the variable Y, which is also an unknown
value. If we later determine that
Y = 10
we then know that
X = 13
Variables in Datalog are just like variables in mathematics.
By convention variables always start with an upper case
letter, e.g., Name, Code, Phone, X, Y, Z, etc.
fact
A fact is the same thing as a tuple in a relation.
It is a true assertion about the enterprise being modelled.
A ground fact has the following general form.
predicate name(list of constants).
where predicate name is the name of a predicate.
The fact is ground because no variables appear in the fact.
Ground facts and predicates are like tuples in relations.
The name of the predicate is effectively just the name of a
relation, and the
list of constants comprise the values of a tuple within that relation.
rules
A rule is a way to derive new facts, that is, a rule is (part of) a
query.
All rules have the following general form.
head :- body
where the head is a single predicate
and the body is a list of predicates.
Each predicate is of the form.
functor(list of constants or variables)
A rule has the following meaning in logic: the ':-' is an implication
symbol (logical IF), and the ',' corresponds to logical AND.
So let's assume we have the rule.
Q :- P
This rules means IF P THEN Q, or in other words, if
P is true then we
can conclude that Q is true, or in other words
P => Q
Modus Ponens is a proof rule in logic that let's us prove new facts.
It is the only such proof rule in Datalog.
Modus Ponens has the following general form. Given that
- '
P => Q' is a true statement and
- '
P' is true
- then we know that '
Q' is true.
Or in other words, in Prolog, if we have some facts that support the
body of a rule, we can conclude that the head is true.
Unification
Unification is the process of making one predicate the same as
another. The end result of unification is that either the two
predicates fail to unify, or they unify with perhaps some binding
of constants to variables, or variables to variables.
Two predicates are said to unify if
-
they have the same name,
-
they have the same number of attributes, and
-
each of their attributes unifies, left to right, using the
following reasoning.
-
If both attributes are constants, they must be the same constant.
-
If one attribute is a constant, and the other a variable, then
the variable is bound to the constant.
-
If both attributes are variables, they are bound to each other.
Let's try to unify some predicates.
Do the following two predicates unify?
-
sameSubject(joe, sue, Code)
-
enrolledIn(joe, cp2001)
No they have different names, and a differing number of attributes.
How about these?
-
enrolledIn(joe, cp2001)
-
enrolledIn(sue, cp2001)
No the first attributes in each are different constants.
How about these?
-
enrolledIn(joe, cp2001)
-
enrolledIn(joe, cp2003)
No the second attributes in each are different constants.
How about these?
-
enrolledIn(Name, cp2001)
-
enrolledIn(sue, cp2001)
Yes, with the caveat that the variable Name = sue (Name is bound to sue).
How about these?
- enrolledIn(Name, cp2001)
-
enrolledIn(sue, Code)
Yes, with the caveat that Name = sue and Code = cp2001.
How about these?
-
enrolledIn(sue, Code1)
-
enrolledIn(sue, Code2)
Yes, with the caveat that Code1 = Code2.
How about these?
-
enrolledIn(X, X)
-
enrolledIn(sue, Y)
Yes, with the caveat that sue = X = Y.
Queries
Prolog queries are evaluated in a top-down manner (from rule heads to
rule bodies). This technique is called backward chaining.
In backward chaining the head is unified, and then we try to prove
each term in the body.
An example will make the process clearer.
Assume that we have the following set of facts.
student(sue, 335-0904).
student(joe, 335-4621).
enrolledIn(joe, cpts355).
enrolledIn(sue, cpts452).
enrolledIn(joe, cpts460).
Further assume that we have one rule.
full(Name, Code, Phone) :- student(Name, Phone), enrolledIn(Name, Code).
Finally, suppose our query is to find out the phone number(s) and names
of those enrolled in cpts355.
? - full(X, cpts355, Y)
To evaluate this query, we will try first try to unify it with the
head of some rule. Well, we have only one rule, so it is pretty easy.
full(Name, Code, Phone)
^
|
full(X, cpts355, Y)
It produces the bindings X = Name, joe = Code, and Y = Phone.
Now let's try to prove the first term in the rule.
student(sue, 355-0904)
unifies with
student(X, Y)
producing the bindings X = sue, Y = 355-0904.
We now try to prove enrolledIn(sue, cpts355).
Nothing unifies with that since sue is not enrolled in cpts355.
So our attempt to prove the body of the rule fails. We try again
with the next student fact.
student(joe, 355-4621)
unifies with
student(X, Y)
producing the bindings X = joe, Y = 355-4621.
We next try to prove enrolledIn(joe, cpts355).
It unifies with the first enrollment fact, so we have
proved full(X, cpts355, Y) with the bindings
X = joe and Y = 355-4621.
In a very real sense, the body of a rule can be viewed as a pattern.
A combination of facts `matches' or `unifies' with the pattern only
under certain assignments of values to the variables. These assignments
are made as new fact are derived.
full(Name, Code, Phone) :- student(Name, Phone), enrolledIn(Name, Code).
| | | ^ ^ ^ ^
\|/ \|/ \|/ | | | |
full(X, cpts355, Y) student(joe, 355-4621), enrolledIn(joe, cpts355).
Source of Information
These lecture notes are based on Chapter 16 in "Programming Languages, 6ed"
by Robert Sebesta.
|