This post follows the tutorial from "Learn Prolog Now!", Chapter 1.
The goal of this post is to introduce the basic concept and syntax of Pilog and to write some first small programs.
The Knowledge Base
In imperative programming, the programmer literally tells the computer what to do step by step. In logical programming it works differently: The programmer writes everything they know into a file and then creates a query on it. The program then deducts logically from the given facts if a statement can be true or false. The file with all the known facts is called the knowledge base.
The knowledge base contains facts and rules. We can work with them by using queries. Facts, rules and queries are clauses. Let's see how they can look like.
Facts
Facts are used to state that things are unconditionally true. For example, let's write the following statements in Pilog (you can start the REPL with pil +
):
: (be likes (John Susie)) # John likes Susie
: (be likes (@X Susie)) # Everyone likes Susie
: (be likes (John @Y)) # John likes everybody
John
and Susie
are constants, likes
is a predicate. Constants can start with an uppercase or lowercase letters (unlike in Prolog, where constants need be lowercase).
On the other hand, @X
and @Y
are variables. All variables start with an @
symbol.
Rules
Rules state things that are conditionally true depending on the given rules.
# X and Y are friends if they like each other
(be friends (@X @Y)
(likes @X @Y)
(likes @Y @X) )
# X hates Y if X does not like Y.
(be hates (@X @Y)
(not (likes @X @Y)) )
# X and Y are enemies if they don't like each other.
(be enemies (@X @Y)
(not (likes @X @Y))
(not (likes @Y @X)) )
Let's call the predicate names with the dependencies friends (@X @Y)
the "left side" and the following statements the "right side" of a clause (this terminology comes from the mathematical notation of logic terms).
We can read the rules as: If the left side is true, then the right side is true. This notation is called a Horn clause. In Horn clause logic, the left hand side of the clause is the conclusion, and must be a single positive literal. The right hand side contains the premises.
In boolean logic, statements can be linked with and
or or
. The "and" is expressed by two consecutive statements in Pilog (see examples), the "or" using the or
function. The negation of a statement is not
.
Creating the knowledge base
Now let's write the following statements into a file called friends.l
.
(be likes (John Susie))
(be likes (John Pizza))
(be likes (Susie John))
(be friends (@X @Y)
(likes @X @Y)
(likes @Y @X) )
(be hates (@X @Y)
(not (likes @X @Y)) )
(be enemies (@X @Y)
(not (likes @X @Y))
(not (likes @Y @X)) )
We have six clauses: three facts and three rules. This is our knowledge base. Let's open it in PicoLisp:
$ pil friends.l +
Now we can run queries no our knowledge base.
Running queries
We can run interactive queries in the REPL with ?
:
: (? (likes John Susie))
-> T
: (? (friends John Susie))
-> T
Susie and John are friends because they mutually like each other.
Now let's try to query for something where we don't have any information about.
: (? (likes Susie Pizza))
-> NIL
? (? (not (likes Susie Pizza)))
-> T
As you can see in the following example, if something cannot be proven correct, then Pilog/Prolog conclude that it is wrong. This is called strong negation. See the following example:
: (? (enemies Susie Pizza))
-> T
We don't know if Susie likes Pizza, and we also don't know if the Pizza likes Susie. Therefore the logical deduction concludes they must be enemies.
This is probably not what we intended. There are alternative ways to define weak negation (if something cannot be proven false, it is correct)
that we will talk about in a later post. For the moment, keep in mind that anything not defined is considered as NIL
.
Working with variables
Now let's write a more interesting one. Let's ask Pilog to return everything that John likes. This "everything" will be represented by a variable in our query. Pilog recognizes variables by the @
symbol at the beginning.
: (? (likes John @X))
@X=Susie
John likes Susie: In other word, we can say that the term (likes John @X)
unifies with the term (likes John Susie)
with (@X = Susie)
. If we now press <Enter>
, we will get additional results:
: (? (likes John @X))
@X=Susie
@X=Pizza
-> NIL
What if we ask for predicates that are not defined in the knowledge base?
: (? (love John Susie))
-> NIL
The query returns NIL
. Similarly when the number of arguments is not matching to the defined predicate:
: (? (likes John Susie Pizza))
-> NIL
So everything we haven't defined is simply NIL
(note that this is different to Prolog where we would receive errors for these cases).
With this, we have already covered the basic Pilog syntax. In the next post we will see how the unification and proof search process actually works.
The friends.l
file can be found here.
Sources
software-lab.de/doc/ref.html#pilog
let.rug.nl/bos/lpn//lpnpage.php?pageid=online
cs.trincoll.edu/~ram/cpsc352/notes/prolog/f..