DEV Community

Cover image for Learning Pilog - 2: Facts, Rules, Queries
Mia
Mia

Posted on • Originally published at picolisp-explored.com

Learning Pilog - 2: Facts, Rules, Queries

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 
Enter fullscreen mode Exit fullscreen mode

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)) )
Enter fullscreen mode Exit fullscreen mode

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)) )
Enter fullscreen mode Exit fullscreen mode

We have six clauses: three facts and three rules. This is our knowledge base. Let's open it in PicoLisp:

$ pil friends.l +
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

What if we ask for predicates that are not defined in the knowledge base?

: (? (love John Susie))
-> NIL
Enter fullscreen mode Exit fullscreen mode

The query returns NIL. Similarly when the number of arguments is not matching to the defined predicate:

: (? (likes John Susie Pizza))
-> NIL
Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)